複数条件で絞り込んで表示する

## 検索用のコンポーネント
検索用のコンポーネントに本のデータを渡して、カテゴリーと出版社データから検索して絞り込めるようにする。

参考にした方法では、検索結果の状態を保存しているので、親コンポーネントの変更が反映されなかった。なので検索条件を保存して、検索結果を保存しないことにした。

カテゴリー、出版社、検索語句で絞り込む。以下のようなjsonオブジェクトをbookとして配列で渡される。

カテゴリーはカンマで区切られているので分割してから検索する。検索語句は全体に検索する。
```json
[
 {
  "Asin": "B0CSYLW8ML",
  "URL": "https://www.amazon.co.jp/dp/B0CSYLW8ML?tag=99hatena-22&linkCode=ogi&th=1&psc=1",
  "ImageURL": "https://m.media-amazon.com/images/I/51hLyvAAPCL._SL500_.jpg",
  "Publisher": "KADOKAWA",
  "Contributor": "日月 ネコ(著)",
  "Booktype": "Kindle版",
  "Title": "理想のヒモ生活(19) (角川コミックス・エース)",
  "Price": 733,
  "Category": "コミック,少年マンガ,カドカワコミックス・エース",
  "Points": 367,
  "Day": 20240202
 },
 {
  "Asin": "B0CQXW5KBP",
  "URL": "https://www.amazon.co.jp/dp/B0CQXW5KBP?tag=99hatena-22&linkCode=ogi&th=1&psc=1",
  "ImageURL": "https://m.media-amazon.com/images/I/515CWzfPjNL._SL500_.jpg",
  "Publisher": "集英社",
  "Contributor": "タカヒロ(著)",
  "Booktype": "Kindle版",
  "Title": "魔都精兵のスレイブ 15 (ジャンプコミックスDIGITAL)",
  "Price": 502,
  "Category": "コミック,少年マンガ,ジャンプコミックス",
  "Points": 133,
  "Day": 20240202
 },
 ]
```
useStateは検索条件を保存する。adultの初期状態はfalseにして、toggle switchでクリックするたびに切り替える。
```jsx
const [adult, setAdult] = useState(false);
if (!adult) {
    const cate = post.Category.split(",");
    a = cate.every(item => item !== "アダルト" && item !== "HOTW_Test_アダルト");
  }
        <input type="checkbox" id="switch" checked={adult} onChange={() => setAdult(prev => !prev)} />
```
filter処理を繰り返さないように。複数の検索条件をまとめて＆＆で複数条件で検索できるようにした。
```jsx
const [adult, setAdult] = useState(false);
const [inputValue, setInputValue] = useState("");
const [selCate, setSelCate] = useState("");
const [selPub, setSelPub] = useState("");

// フィルタリング処理
const filteredList = book.filter((post) => {
  let a = true, c = true, p = true, w = true;

  // アダルトカテゴリを除外
  if (!adult) {
    const cate = post.Category.split(",");
    a = cate.every(item => item !== "アダルト" && item !== "HOTW_Test_アダルト");
  }



  // カテゴリー絞り込み
  if (selCate !== "") {
    const cate = post.Category.split(",");
    c = selCate.some(item => cate.includes(item));
  }

  // 出版社絞り込み
  if (selPub !== "") {
    const pub = post.Publisher.split(",");
    p = selPub.some(item => pub.includes(item));
  }

  // フリーキーワード検索
  if (inputValue !== "") {
    w = Object.values(post).some(item =>
      item &&
      item.toString().toUpperCase().includes(inputValue.toUpperCase())
    );
  }

  return a && c && p && w;
});

// カテゴリー選択
const selectCategory = (category) => {
  setSelCate(category);
};

// 出版社選択
const selectPublisher = (publisher) => {
  setSelPub(publisher);
};

// リセット
const reset = () => {
  setSelPub("");
  setSelCate("");
  setInputValue("");
};

// 入力変更ハンドラ
const handleInputChange = (e) => {
  setInputValue(e.target.value);
};

return (
  <>
    {/* カテゴリー選択ボタン */}
    <div>
      <h4>クリックしてカテゴリーと出版社で絞り込みが可能</h4>
      <p>
        カテゴリー：アダルト許可 
        <input type="checkbox" id="switch" checked={adult} onChange={() => setAdult(prev => !prev)} />
        <button className="categorybutton" onClick={reset}>全て</button>
        {categories.map((category) => (
          <button key={category} className="categorybutton" onClick={() => selectCategory(category)}>
            {category}
          </button>
        ))}
      </p>
      
      {/* 出版社選択ボタン */}
      <details>
        <summary><strong>クリックして出版社選択ボタンの表示</strong></summary>
        <p>
          出版社：
          <button className="categorybutton" onClick={reset}>全て</button>
          {publishers.map((publisher) => (
            <button key={publisher} className="categorybutton" onClick={() => selectPublisher(publisher)}>
              {publisher}
            </button>
          ))}
        </p>
      </details>
    </div>

    {/* フリーキーワード検索フォーム */}
    <div>
      <h4>フリーキーワード検索</h4>
      <input type="text" value={inputValue} onChange={handleInputChange} />
    </div>

    {/* 結果の表示 */}
    <Paginate itemsPerPage={10} items={filteredList} />
  </>
);
```

この記事を参考にした

https://qiita.com/hinako_n/items/a0745afe0631578c698e

https://himenon.github.io/docs/javascript/simple-react-local-search-form/