##はじめに
みなさんこんにちは、ジャケット大好きしろがみです!
Material-Uiにはデータを表の形にして表示をしてくれるTablesというものがあります。
今回はこのTablesで期間検索が出来るようなコードを書いていこうと思います。参考にしていただければ幸いです。
##実装
https://codesandbox.io/s/nifty-gould-51cnj?file=/src/Table.tsx
Table.tsxが該当コードです。
##ポイント
ポイントの解説をします。部分的にソースを貼るので上のリンクと照らし合わせて見ていただけると嬉しいです。
useStateフックを用いて、絞り込みに使用する値filterValue
を作成します。
そして、useEffectフックを用いてこの値が変更した時にfiltering()
関数が実行されるようにします。
このfiltering()
関数の中で絞り込みを行います。
// useStateフックを用いてフィルターに使う値`filterValue`を作成。
const [filterValue, setFilterValue] = useState({
'begin_date' : '',
'end_date' : '',
});
// filterValueが変更した時に、filtering関数、setFilteredData関数を呼び出す。
// rows : フィルターかける前のデータ
useEffect(() => {
// filtering関数 : 絞り込みを行う関数(後述)
const filteringData = filtering(rows, filterValue);
setFilteredData(filteringData);
}, [filterValue])
filtering()
関数の中身についてです。
この関数はfilteringByDate()
関数(後述)を呼び出すだけです。
今後、様々な絞り込みをする可能性が大きいので拡張性を考えてこのようにしています。
function filtering(rawData : { date: string; name: string; }[], filterValue : { [key: string]: string}) {
let filteringData = filteringByDate(rawData, filterValue);
return filteringData;
}
filteringByDate()
関数の中身についてです。
この関数はbeginDate
、endDate
の間に含まれるデータを返す関数です。
function filteringByDate(filteringData : { date: string; name: string; }[], filterValue : { [key: string]: string }) {
if (filteringData === null || filteringData === []) return [];
const beginDate = (function (begin : string) {
// https://262.ecma-international.org/5.1/#sec-15.9.1.1
// Dateの最小値を宣言
let res = new Date(-8640000000000000);
if (begin.length !== 0) {
const result = begin.split('-'); // Expect format '2000-01-01'
res = new Date(parseInt(result[0]), parseInt(result[1])-1, parseInt(result[2]));
}
return res;
})(filterValue['begin_date']);
const endDate = (function (end : string) {
// https://262.ecma-international.org/5.1/#sec-15.9.1.1
// Dateの最大値を宣言
let res = new Date(8640000000000000);
if (end.length !== 0) {
const result = end.split('-'); // Expect format '2000-01-01'
res = new Date(parseInt(result[0]), parseInt(result[1])-1, parseInt(result[2]));
}
return res;
})(filterValue['end_date']);
return filteringData.filter(function (row : { [key: string]: string}) {
const result = row.date.split('/'); // Expect format '2000/01/01'
let rowDate = new Date(parseInt(result[0]), parseInt(result[1])-1, parseInt(result[2]));
return beginDate <= rowDate && rowDate <= endDate;
});
}
入力画面の作成です。
入力画面ですることは、
- 2つ入力フォームを作成する。
- 1つは
filterValue['begin_date']
、もう1つはfilterValue['end_date']
を入力するようにする。
です。こちらもmaterial-uiを使用して実装しました。
return (
<>
<Paper>
<form
noValidate
autoComplete="off"
onSubmit={(e) => e.preventDefault()}
>
<>
<TextField
id="date"
label=""
type="date"
value={filterValue['begin_date']}
{/*アイコン設定*/}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
)
}}
onChange={(e) => {
// hookが反応しないのでdeep copyをしている
let tmp = JSON.parse(JSON.stringify(filterValue));
tmp['begin_date'] = e.target.value;
setFilterValue(tmp);
}}
/>
〜
<TextField
id="date"
label=""
type="date"
value={filterValue['end_date']}
{/*アイコン設定*/}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
)
}}
onChange={(e) => {
// hookが反応しないのでdeep copyをしている
let tmp = JSON.parse(JSON.stringify(filterValue));
tmp['end_date'] = e.target.value;
setFilterValue(tmp);
}}
/>
</>
</form>
</Paper>
// テーブルは略
</>
)
注意するのは下の部分です。
let tmp = filterValue;
とすると、中身の値自体は変更されますが、filterValue
自体を表す参照値が変化しないので、絞り込み処理が行われません。
そのため、一度deep copyを行っています。
onChange={(e) => {
// hookが反応しないのでdeep copyをしている
// let tmp = filterValue;としてはhookが反応しない。
let tmp = JSON.parse(JSON.stringify(filterValue));
tmp['begin_date'] = e.target.value;
setFilterValue(tmp);
}}
おわりに
今回はmaterial-uiのTableに期間絞り込み機能の実装例を紹介しました。いかがだったでしょうか?
内容としてはuseStateやuseEffectといったReactの初歩的な内容ですが、手助けになったのなら嬉しいです。また、今回の実装を用いると新しく絞り込みを追加したりということもやりやすいと思います。
個人的な話になりますが、自分はReactを書くのが1年ぶりなのでよっても良い復習になりました。これから仕事でばりばりReactを書くことになると思うので、なにか気づいたことがあればまた共有します!