React hooksで複合的な絞り込み検索機能を作る

React hooks で絞り込み検索機能を実装してみます。
今回は、データの配列に対して、入力フォームの値とチェックボックスの状態との複合条件で絞り込みができるようにします。

リストを表示
まずは簡単なデータの配列を用意し、全容をリストとして画面表示していきます。
const persons = [
  { name: 'Terence', sport: 'baseball' },
  { name: 'Lukas', sport: 'soccer' },
  { name: 'Bernhard', sport: 'tennis' },
  { name: 'Oliver', sport: 'basketball' },
  { name: 'Sherrington', sport: 'soccer' },
  { name: 'Nahum', sport: 'basketball' },
  { name: 'Luis', sport: 'soccer' },
  { name: 'Ricard', sport: 'tennis' },
]
export const App = () => {
  const datas = persons;
  return (
    <>
      <ul>
        {datas.map((data) => (
          <li key={data.name}>{data.name}, {data.sport}</li>
        ))}
      </ul>
    </>
  );
}
入力フォームを追加
input を追加し、onchange を適用して入力値を useState で管理できるようにします。
import { useState } from "react";
export const App = () => {
  const [name, setName] = useState('');
  const onChangeName = (event) => setName(event.target.value);
  const datas = persons;
  return (
    <>
      <p>
        name: <input type="text" onChange={onChangeName} />
      </p>
      <ul>
        {datas.map((data) => (
          <li key={data.name}>{data.name}, {data.sport}</li>
        ))}
      </ul>
    </>
  );
}
onchange を使うと、イベントの情報が含まれたデータ (event) を関数の引数として受け取ることができます。入力フォームの値は event.target.value で取得できるので、これを useState の set 関数を使って state を更新します。
チェックボックスを追加
同様にチェックボックスを追加します。チェックボックスは複数選択ができるようにしたいので、state の値は配列としています。
export const App = () => {
  const [name, setName] = useState('');
  const [sports, setSports] = useState([
    'baseball',
    'soccer',
    'tennis',
    'basketball',
  ]);
  const onChangeName = (event) => setName(event.target.value);
  const onChangeSport = (event) => event.target.checked
    ? setSports([...sports, event.target.value])
    : setSports(sports.filter((sport) => sport.match(event.target.value) === null));
  const datas = persons;
  return (
    <>
      <p>
        name: <input type="text" onChange={onChangeName} />
      </p>
      <p>
        sports:
        <input type="checkbox" value='baseball' onChange={onChangeSport} defaultChecked />baseball  
        <input type="checkbox" value='soccer' onChange={onChangeSport} defaultChecked />soccer  
        <input type="checkbox" value='tennis' onChange={onChangeSport} defaultChecked />tennis  
        <input type="checkbox" value='basketball' onChange={onChangeSport} defaultChecked />basketball  
      </p>
      <ul>
        {datas.map((data) => (
          <li key={data.name}>{data.name}, {data.sport}</li>
        ))}
      </ul>
    </>
  );
}
初期状態ではリストを全表示するようにしたいので、チェックボックスを全て ON とし ( defaultChecked )、state にも全要素からなる配列を入れておきます。
また、onChange で利用する関数を以下のように定義しています。
const onChangeSport = (event) =>
  event.target.checked
    ? setSports([...sports, event.target.value])
    : setSports(sports.filter((sport) => sport.match(event.target.value) === null));
チェックボックスが ON / OFF どちらになったのかは event.target.checked で取得できるので、これによって state に入れる値を場合分けします。
ON になった場合は、現在の state の配列に新たにチェックされた値を追加します。複数のチェックボックスのうち、どのチェックボックスが操作されたかは、入力フォームと同じ event.target.value で取得できるので、現在の state の値 sports とを組み合わせて [...sports, event.target.value] のような形で state を更新します。
一方で OFF になった場合は、現在の state の配列から対象の要素を削除します。ここでは filter を使って OFF となった要素を配列の中から抽出して削除するようにしています。
絞り込み
入力フォームとチェックボックスの state が取得できたので、これを使ってリストの表示を絞り込んでいきます。
export const App = () => {
  // const datas = persons; // <- 削除
  let datas = persons.filter((data) => data.name.match(name)); // <- 追加
  datas = datas.filter((data) => sports.includes(data.sport)); // <- 追加
  return (
    ...
  )
filter を使い、入力フォームの値 name の文字列を含む要素だけに絞り込みます。その絞り込まれた配列に対してさらに filter を適用し、チェックボックス の配列 sports に含まれる要素だけに絞り込みます。
ちなみに、英大文字と英小文字を区別したくない場合は、正規表現を生成する RegExp を使って以下のように書き換えます。
const reg = new RegExp(name, 'i');
let datas = persons.filter((data) => data.name.match(reg));
これでリストの絞り込み検索ができるようになりました。