【React Table v7 → v8】【TypeScript 】アップデートの勘所


こんにちはフロントエンドエンジニアの茶木です。
前回まで React Table を v7 で、TypeScript で型付けしながら書いていたのですが、年も明けたことですし、 v7 から v8 に アップデートしていきます。

ファイル構成

pages/index.tscomponents/Table/index.ts の Table コンポーネントを呼び出す想定です。

基本の構成は v7 と変えていませんが、1ファイル1コンポーネントになるように書き直しています。

├ components/
│ └ Table/
│   ├ Header/
│   │ ├ index.tsx
│   │ ├ Row.tsx
│   │ └ Cell.tsx
│   ├ Body/
│   │ ├ index.tsx
│   │ ├ Row.tsx
│   │ └ Cell.tsx
│   ├ Cell/
│   │ └ DateCell.tsx
│   ├ index.tsx
│   └ TableContent.tsx
└ pages/
    └ index.ts

Columnsの定義

大きな変更のある箇所について述べていきます。

まず、Columnsの定義ですが、createColumnHelper という関数が使えるようになりました。v7 では accessor: "id" as const といったように書いていた箇所が読みやすくなります。

import { createColumnHelper } from "@tanstack/react-table";
const columnHelper = createColumnHelper<MatchResult>();

const columns = [
  columnHelper.accessor("id", {
    header: "id",
  }),
  columnHelper.accessor("updatedTimestamp", {
    header: "更新日",
    cell: DateCell,
  }),
];

また、ここで columns の型は、 v7では Column<R>[] だったものが、 ColumnDef<R, D>[] に変わります。R は各行が持つ列の形式で、表示するテーブルによって変えるためにジェネリクスの形式をとっています。こちらは v7 の方と変わりません。

interface RowSample{
  id: string;
  updatedTimestamp: number;
}

そして D は、各列の値の型の union type になる模様です。 (後述)

useReactTable

v7 で useTable だったものは v8 では useReactTable に変わっています。
data は R型を持つ rows で React Table で管理する値になります。columns は先程の columns定義になります。v8 では、さらに getCoreRowModel というのを渡します。getCoreRowModel() はライブラリから提供されています。

  const table = useReactTable<R>({
    data: rows,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

行の描画

v7 では行の生成に table.rowstable.prepareRow を使っていましたが、 v8 では、table.getRowModel().rows を使います。rows.map で各行を描画します。

<MuiTableBody>
  {table.getRowModel().rows.map((row) => (
    <TableRow key={row.id} row={row} />
  ))}
</MuiTableBody>

列の描画

v7 では列の描画に row.cells を使いましたが、 v8 では、 row.getVisibleCells() を使います。row.getVisibleCells().map で各行を描画します。

<MuiTableRow>
  {row.getVisibleCells().map((cell) => (
    <TableCell key={cell.id} cell={cell} />
  ))}
</MuiTableRow>

セルの描画

v7 では cell.render("Cell") を使いましたが、 v8 では、 flexRender() を使います。コードは下記のとおりです。

<MuiTableCell>
  {flexRender(cell.column.columnDef.cell, cell.getContext())}
</MuiTableCell>

個別の装飾セル

columns にわたす Cellコンポーネントの説明をします。v7 では props.value で値を取得していましたが、v8 では props.getValue() を使用します。

例では、timestamp を年月日に加工しています。

<>
  {format(new Date(props.getValue()), "yyyy-MM-dd")}
</>

テーブルヘッダー

端折って説明します。

table.getHeaderGroups() から headerGroups 生成します。headerGroups配列の要素 headerGroupheaderGroup配列の要素 headerTableBodyのセルに相当し、こちらも flexRender を使って描画します。

TypeScript ハマりポイント

以上が v7 から v8 への移植の基本的な説明でした。

1点ハマりポイントがあり、Columns定義を Tableコンポーネントにわたす際の、Tableコンポーネントの props の型定義をどうするか、です。

ColumnDef<R, D>[]の形をとると述べました。Dは、各列の値の型の union type になるので、(一手間かければ)Rからうまく抽出できそうなのですが、data に含まれる行のすべてを使わない場合、columns と不一致になってしまうので、厳密性と利便性を天秤にかけて Dany を設定しています。研究の余地ありです。

columns: ColumnDef<R, any>[];

おわりに

v7 から v8 に代わり、値の取得の箇所がメソッドに大きく変わっている点を注意すれば、比較的難しくなく移管できると思います。

Gaji-Laboでは、React経験が豊富なフロントエンドエンジニアを募集しています

弊社ではReactの知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違うGaji-Laboを味わいに来ませんか?

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

投稿者 Chaki Hironori

webライターもやってるフロントエンドエンジニアです。Reactは自信があります。またデザイン畑の出身で、気持ちのいいアニメーションやインタラクティブな表現は丁寧に手掛けます。好きなものは中南米の遺跡で、スペイン語が少しできます。