material-table でコンポーネント再描画時にフィルターがリセットされてしまう現象を対処する
はじめに
テントの中から失礼します、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
今回は以上になります。最後まで読んで頂きありがとうございました!