準備
適当なコンポーネントファイルを作り作成しましょう。
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>
);
