React 配列を使用したチェックボックスの実装

# 成果物
今回作成したのは、配列を使用したセレクトボックスです。
チェックされた項目が配列として表示されます。
ただし、配列はチェックされた順に作成されるため、セレクトボックスの並び順で配列が表示されるわけではありません。

https://codesandbox.io/embed/tietukubotukusu-arenzi-w5qdjd?fontsize=14&hidenavigation=1&theme=dark

# コード
## index.js
```javascript
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
```

## App.js
```javascript
import React, { useState } from "react";
import "./styles.css";

// チェックボックスにセットしたい項目の配列itemsを設定する
const items = [
  { id: 1, item: "読書" },
  { id: 2, item: "スポーツ" },
  { id: 3, item: "旅行" },
  { id: 4, item: "音楽" }
];

// 親コンポーネントInputCheckBoxからprops(handleChange, checkedValues)を受け取る
const CheckBtnItems = (props) =>

  // map()で配列itemsから要素を1つずつ取り出し処理する
  items.map((item) => {
    return (
        
      // key属性（チェックボックス内で一意の値)を設定する
      <label key={item.id}>
        <input
          type="checkbox"

          // value属性にitem.itemを設定する
          value={item.item}

          // セレクトボックスがチェックされた、またはチェックが外れた際に関数handleChangeが実行される
          onChange={props.handleChange}

          // checked属性はページが読み込まれたときにチェックされているかどうかを示します
          // チェックボックスが現在チェックされているかどうかを示すものではありません
          // チェックボックスの状態が変化した場合、このコンテンツ属性は変化を反映しません
          // 初期状態では現在のセレクトボックスの状態を管理する配列checkedValuesは
          // 配列itemsの要素itemを含んでいないため、デフォルトではセレクトボックスは全て空になっています
          checked={props.checkedValues.includes(item.item)}
        />
        {item.item}
      </label>
    );
  });

const InputCheckBox = () => {
   
  // 現在選択されているチェックボックスの状態の配列checkedValues
  // checkedValuesの状態を更新する関数setCheckedValues
  // 初期値は空の配列[]を設定
  const [checkedValues, setCheckedValues] = useState([]);

  // セレクトボックスがチェックされた、またはチェックが外れた際に関数handleChangeが実行される
  const handleChange = (e) => {
    
    // チェックされた、またはチェックが外れたセレクトボックスのvalue属性が
    // 配列checkedValuesに含まれているか判定する
    if (checkedValues.includes(e.target.value)) {

      // チェックされた、またはチェックが外れたセレクトボックスが既に配列checkedValuesに含まれている場合
      // 簡単に言うと、チェックが外された場合
      setCheckedValues(

        // 配列checkedValuesの要素の中からチェックが外されたセレクトボックスのvalueと一致する要素を
        // 除いた配列を新たに作成する
        checkedValues.filter((checkedValue) => checkedValue !== e.target.value)
      );

    // チェックされた、またはチェックが外れたセレクトボックスが既に配列checkedValuesに含まれていない場合
    // 簡単に言うと、チェックされた場合    
    } else {

      // チェックされたセレクトボックスのvalueを配列checkedValuesに追加する
      setCheckedValues([...checkedValues, e.target.value]);
    }
  };

  return (
    <div className="App">
      <p>
        // checkedValues.join("、　 ")で配列checkedValuesの要素を"、 "で結合した
        // 文字列を作成する
        あなたの趣味はなんですか:<b>{checkedValues.join("、 ")}</b>
      </p>
      <CheckBtnItems

        // 子コンポーネントCheckBtnItemsにhandleChange, checkedValuesを渡す
        handleChange={handleChange}
        checkedValues={checkedValues}
      />
    </div>
  );
};

export default function App() {
  return <InputCheckBox />;
}
```

## styles.css
```css
label {
  display: block;
}
```

<br>

### Array.includes()
`Array.includes(arg)`を利用すると配列`Array`に`arg`が含まれているか真偽値で返します。
配列`Array`の要素に`arg`が含まれている場合、`true`を返す
配列`Array`の要素に`arg`が含まれていない場合、`false`を返す

### Array.filter()
`Array.filter((arg) => ...)`を利用すると`...`の条件に一致する要素のみで新たな配列を作成する