準備
適当なコンポーネントファイルを作り作成しましょう。
importするのはuseState
とuseMemo
import React, { useState, useMemo } from 'react'; export default () => { // ここにコードを追加していきます。 };
初期データ(initialState)
initialState
として最初に表示されるデータを作成します。
実際のアプリケーションでは必要ないかもしれませんが、今回はサンプルの動きを見るために作成してます。
今回の検索は、テキスト入力でのタイトル検索と、セレクトボックスでのカテゴリーの検索をできるようにします。
const initialState = { tasks: [ { id: 1, title: '最初のタスク', category: 1 },{ id: 2, title: '2番目のタスク', category: 2 },{ id: 3, title: '3番目のタスク', category: 1 } ], categories: [ { id: 1, title: 'カテゴリー1' },{ id: 2, title: 'カテゴリー2' } ] };
Stateの作成
React Hooks でのステートはuseState
を使用します。
引数には、初期データを指定します。
戻り値の配列の一つ目の変数でステートの値を取得して、2つ目の変数でステートを更新します。
今回作成するステートは4つです。
データとして、タスク、カテゴリーと、検索条件を保存するステートとして、filterQuery
とsort
を作成します。
// タスク const [tasks, setTasks] = useState(initialState.tasks); // カテゴリー const [categories, setCategories] = useState(initialState.categories); // 検索条件 const [filterQuery, setFilterQuery] = useState({}); // ソート条件 const [sort, setSort] = useState({});
検索・並び替え機能
メインとなる検索・並び替え機能にはuseMemo
を使います。
第2引数の配列を指定することで、この変数の変化がある度にこの部分の処理が実行されます。
const filteredTask = useMemo(() => { let tmpTasks = tasks; // 入力した文字は小文字にする const filterTitle = filterQuery.title && filterQuery.title.toLowerCase(); // 絞り込み検索 tmpTasks = tmpTasks.filter(row => { // タイトルで絞り込み if ( filterQuery.title && String(row.title).toLowerCase().indexOf(filterTitle) === -1 ) { return false; } // カテゴリーで絞り込み if ( filterQuery.category_id && row.category !== parseInt(filterQuery.category_id) ) { return false; } return row; }); // ソート if (sort.key) { tmpTasks = tmpTasks.sort((a, b) => { a = a[sort.key]; b = b[sort.key]; return (a === b ? 0 : a > b ? 1 : -1) * sort.order; }); } return tmpTasks; }, [filterQuery, sort, tasks]);
イベントハンドラ
検索・並び替えそれぞれのイベントハンドラを作成します。
並び替え(Sort)はkey
とorder
を設定できるようにして、カラムを設定した場合は逆順になるようにorder
をマイナスにします。
// 入力した情報をfilterQueryに入れる const handleFilter = e => { const { name, value } = e.target; setFilterQuery({ ...filterQuery, [name]: value }); }; // 選択したカラムをSortに入れる const handleSort = column => { if (sort.key === column) { setSort({ ...sort, order: -sort.order }); } else { setSort({ key: column, order: 1 }) } };
JSX
最後にJSXから、イベントハンドラを実行できるように設定しましょう。
タイトル検索はinputのtextに、カテゴリーはselectにそれぞれonChange
でhandleFilter
設定します。
ソートはtableのthをクリックすることで実行されるようにするのでonClick
でhandleSort
を使用します。
return ( <div className="wrap"> <div className="filter-box"> <div className="input-group"> <input type="text" name="title" className="form-input" placeholder="タイトル" value={filterQuery.title || ''} onChange={handleFilter} /> </div> <div className="input-group"> <div className="selectbox"> <select name="category_id" value={filterQuery.category_id} onChange={handleFilter} > <option value="">カテゴリー選択</option> { categories.map((item) => { return ( <option key={item.id} value={item.id}> {item.title} </option> ); }) } </select> </div> </div> </div> <table> <thead> <tr> <th onClick={() => handleSort('id')}>ID</th> <th>タイトル</th> <th onClick={() => handleSort('category')}>カテゴリー</th> </tr> </thead> <tbody> { filteredTask.map((task) => { return( <tr key={task.id}> <td>{task.id}</td> <td>{task.title}</td> <td> { task.category ? categories.find(c => c.id === task.category).title : '' } </td> </tr> ); }) } </tbody> </table> </div> );