おはこんばんにちは、フリーランスエンジニアのせなです。
最近ReactでWebアプリを開発する際にMaterial React Tableのフィルターを作成する方法が分からなかったので備忘録も兼ねて紹介したいと思います。
プロジェクトのソースコードはGitHubにあげています。
詳細が気になる方はそちらも参照してください。
事前準備
今回はYarnを使ってプロジェクトを作成します。
その他の方法でプロジェクトを作成する場合は適宜読み替えてください。
cd /path/to/your/project
yarn create react-app app --template typescript
cd app
yarn add material-react-table @mui/material @mui/x-date-pickers @mui/icons-material @emotion/react @emotion/styled dayjs
# ↓はフィルターとは関係ありません。
# プロジェクト作成時に必要だった最低限のライブラリです。
yarn add react-router-dom tailwindcss
ディレクトリ構成
今回は以下のディレクトリ構成で作成します。
今回のフィルター説明とは直接関係はないので、読み飛ばしても大丈夫です。
app
├── src
│ ├── App.tsx - メインコンポーネント
│ ├── providers
│ │ ├── app.tsx - プロバイダー
│ ├── routes
│ │ ├── index.tsx - ルーティング
│ ├── features
│ │ ├── table
│ │ │ ├── components
│ │ │ │ ├── UserTable.tsx - テーブルコンポーネント
│ │ │ │ ├── CustomDatePicker.tsx - 日付ピッカーコンポーネント
│ │ │ ├── filters
│ │ │ │ ├── dateFilter.ts - 日付フィルター(今回の本題)
│ │ │ ├── routes
│ │ │ │ ├── index.ts - ルーティング
│ │ │ │ ├── TableRoute.tsx - テーブルのルーティング
フィルターの作成方法
ここからが本題です。
フィルターを作成するためには、MRT_FilterFn
を使用します。
以下は、日付の範囲を指定するフィルターの例です。
import { MRT_FilterFn } from "material-react-table";
const dateFilter: MRT_FilterFn<any> = (
row,
columnId,
filterValue,
) => {
const rowValueDate: Date = row.getValue(columnId);
const filterStartDate = filterValue[0];
const filterEndDate = filterValue[2];
if (filterStartDate && filterEndDate) {
// 期間の開始・終了が指定されている場合
const isValid = rowValueDate >= filterStartDate && rowValueDate <= filterEndDate;
return isValid;
} else if (filterStartDate && !filterEndDate) {
// 期間の開始が指定されている場合
const isValid = rowValueDate >= filterStartDate;
return isValid;
} else if (!filterStartDate && filterEndDate) {
// 期間の終了が指定されている場合
const isValid = rowValueDate <= filterEndDate;
return isValid;
} else {
// 期間が指定されていない場合
return true;
}
}
export default dateFilter;
このフィルターを使用するためには、useMaterialReactTable
のfilterFns
に登録する必要があります。
以下は、useMaterialReactTable
のサンプルコードです。
const table = useMaterialReactTable({
columns,
data,
initialState: {
showColumnFilters: true,
showGlobalFilter: true,
},
enableColumnResizing: true, // 列幅変更
enableColumnFilters: true, // 列フィルター
enableRowSelection: false, // 行のチェックボックス
enableFilterMatchHighlighting: false, // フィルターのハイライト
enableColumnFilterModes: true, // 列フィルターモード
enableColumnDragging: false, // 列ドラッグ
enableColumnOrdering: false, // 列並び替え
enableColumnPinning: true, // 列固定
enableColumnActions: false, // 列アクション
filterFns: {
// 日付のフィルター処理
'dateFilter': dateFilter as FilterFn<any>,
},
state: {
columnFilters,
globalFilter,
isLoading
},
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
});
そして、fileterFns
に登録したdateFilter
を使用するカラムのfilterFn
に指定します。
{
accessorKey: 'birthday',
header: '誕生日',
minSize: 75,
maxSize: 400,
size: 125,
enableSorting: false, // ソートを無効
enableColumnActions: false, // : のカラムアクションを無効
enableColumnFilter: false, // カラムのフィルター表示を無効
filterFn: 'dateFilter',
},
これで、誕生日の範囲を指定してフィルターを行うことができるようになっているかと思います。
以下のような、日付を選択するコンポーネントを作成して、フィルターを行うことができます。
const header = table.getHeaderGroups()[0]
const birthdayColumn = header.headers[2].column // 誕生日カラム
const [startDateFilterValue, setStartDateFilterValue] = useState<string | null>(dayjs().year(2024).month(0).date(1).format("YYYY/MM/DD"));
const [endDateFilterValue, setEndDateFilterValue] = useState<string | null>(dayjs().year(2024).month(1).date(-1).format("YYYY/MM/DD"));
return (
<div className="flex flex-col justify-center items-center w-full min-h-screen">
<CustomDatePicker
value={dayjs(startDateFilterValue).format("YYYY-MM-DD") ?? ''}
onChange={(value: string) => {
birthdayColumn.setFilterValue((old: [string, string, string, string]) => [value, old?.[1], old?.[2], old?.[3]])
setStartDateFilterValue(value);
}}
label="開始日"
className="w-40"
/>
<CustomDatePicker
value={dayjs(endDateFilterValue).format("YYYY-MM-DD") ?? ''}
onChange={(value: string) => {
birthdayColumn.setFilterValue((old: [string, string, string, string]) => [old?.[0], old?.[1], value, old?.[3]])
setEndDateFilterValue(value);
}}
label="終了日"
className="w-40"
/>
<div className="w-5/6">
<MaterialReactTable table={table} />
</div>
</div>
);
以上で、MRTのテーブルにフィルターを作成する方法を紹介しました。
まとめ
今回説明した方法は日付をフィルターする方法ですが、他のフィルターも同様の方法で作成することができます。
例えば日時(datetime)のフィルターについては以下にサンプルコードをあげていますので、参考にしてみて下さい。
datetimeFilter.ts
他にもっと良い方法があるよ! って方がいればコメントで教えてもらえると嬉しいです!
ではでは〜