Reactで曜日選択の切り替え動作を実装

## はじめに
時間割アプリの開発にあたって、曜日選択機能を実装しました。
その際に記述したコードとその解説をしていきます。

### 機能の詳細
- 完成時の画面表示![スクリーンショット 2024-09-30 11.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3842446/63d526da-821a-ddd7-cb87-80578ad8b998.png)
- 実装する機能
1\.初期状態は先頭の`li`タグを黄色表示
2\.`li`タグをクリックすると黄色くなり、すでに黄色い`li`タグは青に戻る
- 最終的なコード
```WeekSelect.jsx
import styled from "styled-components";
import { useState } from "react";

// Styled components
const WeekList = styled.ul`
  width: 500px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 auto 30px auto;
`;

const WeekItem = styled.li`
  width: 50px;
  height: 50px;
  color: #fff;
  font-size: 24px;
  font-weight: bold;
  border-radius: 2px;
  display: flex;
  flex-direction: column;
  text-align: center;
  justify-content: center;
  background-color: ${(props) => (props.selected ? "#F6D534" : "#2c65c7")};
  cursor: pointer;
  transition: background-color 0.3s ease;

  &:hover {
    background-color: ${(props) => (props.selected ? "#F6D534" : "#4169e1")};
  }
`;

// Main component logic
export const WeekSelect = () => {
  const [selectedIndex, setSelectedIndex] = useState(0);

  const weekDays = ["全", "火", "木", "金", "土", "日"]; // 曜日データ

  const handleClick = (index) => {
    setSelectedIndex(index); // クリック時にインデックスを更新
  };

  return (
    <>
      <WeekList>
        {weekDays.map((day, index) => (
          <WeekItem
            key={index}
            selected={selectedIndex === index} // propsとしてselectedを渡す
            onClick={() => handleClick(index)} // クリックイベントハンドラ
          >
            {day}
          </WeekItem>
        ))}
      </WeekList>
    </>
  );
};

```

### 解説
#### マークアップの構造
`ul`タグ内に`li`タグがあり、`li`タグの中に曜日名が格納されている状態
```WeekSelect.jsx
      <WeekList>
          <WeekItem>
            {day}
          </WeekItem>
      </WeekList>
```
#### 初期状態の表示
`useState`の初期値を配列の0番目にしておくことで、先頭の`li`タグ(全)を指定。
また、`WeekItem`(`li`タグ)に`props`として`selected`を渡す。
結果スタイル部分で三項演算子を用いて「選択状態なら黄色、出なければ青」を表示できる。
初期状態`index`は配列の0番目を表しているため、先頭の`li`タグが選択状態になり黄色く表示される。

```WeekSelect.jsx
const WeekItem = styled.li`
 // 省略
 background-color: ${(props) => (props.selected ? "#F6D534" : "#2c65c7")};
 `

 export const WeekSelect = () => {
  const [selectedIndex, setSelectedIndex] = useState(0);

  const weekDays = ["全", "火", "木", "金", "土", "日"]; // 曜日データ

  const handleClick = (index) => {
    setSelectedIndex(index); // クリック時にインデックスを更新
  };

  return (
    <>
      <WeekList>
        {weekDays.map((day, index) => (
          <WeekItem
            key={index}
            selected={selectedIndex === index} // propsとしてselectedを渡す
            onClick={() => handleClick(index)} // クリックイベントハンドラ
          >
            {day}
          </WeekItem>
        ))}
      </WeekList>
    </>
  );
};

```

#### クリックイベント
`onClick`関数を用いる。
`handleClick`関数の`index`を引数に渡したいので、アロー関数の形をとる。
`handleClick`関数はクリックしたときに更新関数に`index`を渡すことで状態を更新する。
結果クリックした時に`index`を取得し、`selected`に基づいて変化した状態が再レンダリングによって反映される。

```WeekSelect.jsx
export const WeekSelect = () => {
  const [selectedIndex, setSelectedIndex] = useState(0);

  const weekDays = ["全", "火", "木", "金", "土", "日"]; // 曜日データ

  const handleClick = (index) => {
    setSelectedIndex(index); // クリック時にインデックスを更新
  };

  return (
    <>
      <WeekList>
        {weekDays.map((day, index) => (
          <WeekItem
            key={index}
            selected={selectedIndex === index} // propsとしてselectedを渡す
            onClick={() => handleClick(index)} // クリックイベントハンドラ
          >
            {day}
          </WeekItem>
        ))}
      </WeekList>
    </>
  );
};
```

#### 備考
`map`関数で配列の各要素に対してループを行う。
{day}はループ内での現在の要素を表しており`index`はその要素が何番目かを表している。
また、`li`タグに直接`props`を渡すと、意図しない属性がそのままDOMに出力されてしまうことがある。
そのため、`li`タグを`WeekItem`として新しく`styled`コンポーネントにし、`selected`という名前で`props`を受け取るようにしている。

## さいごに
もし言葉不足や誤解を生む表現、誤った描写があれば教えていただけると助かります。
また、別のもっと適切な方法があればぜひ教えていただきたいです。

> 時間割アプリで使用した他の機能はこちら

https://qiita.com/naoki-atjp/items/bc8a7028aba7d3725832

https://qiita.com/naoki-atjp/items/43aab60a1ff7e6bc8291

https://qiita.com/naoki-atjp/items/e890c89452dec8573fbd

https://qiita.com/naoki-atjp/items/d361465174a20abf84f4