この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
テントの中から失礼します、CX事業本部のてんとタカハシです!
Material-UI のテーブルを基に作られた material-table のフィルターですが、コンポーネントの再描画が走ると、フィルターが勝手にリセットされてしまう現象が発生しまして、それを対処したので記事にしようと思います。
material-table のフィルターとはなんぞやって思った方には、以前ブログに書いた下記の記事を読んで頂けると、概要が分かるかと思います。
material-table で日付範囲の指定によるフィルタリングがしたい
また、対処後のソースコードを下記のリポジトリに置いていますので、参考にして頂ければと思います。
GitHub - iam326/material-table-filter-reset-when-re-rendering-component
環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.6
BuildVersion: 19G2021
$ node --version
v12.18.2
$ yarn --version
1.22.4
$ yarn list --depth=0
...
├─ @material-ui/core@4.11.0
├─ material-table@1.68.0
├─ react@16.13.1
├─ typescript@3.7.5
...
現象
例えば、material-table で作ったクーポン一覧テーブルがあるとします。行をクリックしてクーポンを選択すると、背景の色が変わり、クーポンを使用するためのボタンが押せるようになる感じの UI を想定します。
ソースコードを下記に記載します。
行をクリックした際の処理は、onRowClick
に記述します。今回は行をクリックした際、どのクーポンを選んだかを記録しておくために、selectedCouponId
という state を更新する処理を実装しています。
また、options に filtering: true
を渡して、全ての列に文字列の部分一致によるフィルターを設置します。
const DataTable: React.FC = () => {
const [selectedCouponId, setSelectedCouponId] = useState<string | null>(null);
return (
<MaterialTable
options={{
search: false,
draggable: false,
filtering: true, // ★ 全ての列にフィルターを設置
rowStyle: (rowData) => ({
backgroundColor: selectedCouponId === rowData.couponId ? '#eee' : '',
}),
}}
onRowClick={(_, rowData) => // ★ 行クリック時の処理
setSelectedCouponId(
rowData &&
(!selectedCouponId || selectedCouponId !== rowData.couponId)
? rowData.couponId
: null
)
}
actions={[
{
icon: () => (
<Button
variant="contained"
color="primary"
disabled={!selectedCouponId}
>
使用する
</Button>
),
disabled: !selectedCouponId,
isFreeAction: true,
onClick: () => alert('Button Click!!'),
},
]}
columns={[
{
title: 'クーポン ID',
field: 'couponId',
},
{ title: '店舗', field: 'storeName' },
{
title: 'クーポン名',
field: 'couponName',
},
{
title: '割引率',
field: 'discountRate',
cellStyle: { textAlign: 'right' },
},
{
title: '利用開始日',
field: 'startDate',
cellStyle: { textAlign: 'right' },
},
{
title: '利用終了日',
field: 'endDate',
cellStyle: { textAlign: 'right' },
},
]}
data={tableData}
title="クーポン一覧"
/>
);
};
では、このテーブルに対して、店舗名に「秋葉原」を含むクーポンのみ表示させるよう、フィルタリングを適用してあげます。
その後、行をクリックしてクーポンを選択すると、フィルターが勝手にリセットされ、全てのクーポンが表示されてしまいます。行をクリックしたことで selectedCouponId
が更新され、コンポーネントの再描画が走り、列情報がリセットされた結果、この現象が起きてしまうということが考えられます。
対処法
簡単です。列情報自体を state 化するだけで、この現象を対処できます。これでコンポーネントの再描画が走っても列情報を維持することができます。
const [columnInfo] = useState<Array<Column<Coupon>>>([ // ★ 列情報を state 化
{
title: 'クーポン ID',
field: 'couponId',
},
...
<MaterialTable
...
columns={columnInfo} // ★ state 化した列情報を渡す
data={tableData}
title="クーポン一覧"
/>
フィルタリング適用後に、行をクリックしてクーポンを選択しても、フィルターはそのまんまになりました!
おわりに
今回は、material-table でコンポーネント再描画時にフィルターがリセットされてしまう現象の対処方法についてご紹介しました。
material-table が標準で用意しているフィルターと、行クリック時の処理を単純に組み合わせた結果、この現象が発生してしまいました。最初はどう対処すれば良いのか見当がつかなかったのですが、GitHub の Issue を探っていたら、同じような現象で困っている人がいて、その中のコメントで答えを見つけることができました。めちゃ助かった。
Issues - Filtering states reset upon rerendering remote table
今回は以上になります。最後まで読んで頂きありがとうございました!