React Table v8 で 外から判定のルールを渡せるフラグを表示するセルを作る


こんにちはフロントエンドエンジニアの茶木です。
前回の記事で、React Table V8 で 行ごとの任意の cell の 値にアクセスしてフラグを表示するセルを作成しました。

前回記事の振り返り

const columnHelper = createColumnHelper<Forum>();

const columns = [
  {
    header: "フラグ",
    cell: FlagCell,
  },
  columnHelper.accessor("unread", {
    header: "未読数",
  }),
  columnHelper.accessor("timestamp", {
    header: "更新日",
    cell: DateCell,
  }),
  columnHelper.accessor("title", {
    header: "タイトル",
  }),
];

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

このような columns で示されるようなテーブルがあったとします。フラグ、未読数、更新日、タイトルという列を持ちますが、フラグはそれ以外の列から計算されるものとします。

type Props = CellContext<Folum, undefined>
export const FlagCell = (props: Props): ReactElement => {
  const { unread } = props.row.origin;
  return <Cell>{ unread > 0 ? "🚩" : " " }</Cell>;
};

たとえば、未読があればフラグを表示するセルならこのように、

import { isToday } from "date-fns";

type Props = CellContext<Folum, undefined>
export const FlagCell = (props: Props): ReactElement => {
  const { timestamp } = props.row.origin;
  const date = new Date(timestamp);
  return <Cell>{ isToday(date) ? "🚩" : " " }</Cell>;
};

たとえば、本日の更新があればフラグを表示するセルならこのように書けます。

でも、見た目の部分は共通なので、判定のルールは 外から渡せると汎用的になりそうです。React Table の Cell に外から値を渡す方法についてまとめます。

column の meta プロパティを使う

const columns = [
  columnHelper.accessor("id", {
    header: "フラグ",
    cell: FlagCell,
    meta: { rule: "unread" },
  }),
]

columnmeta プロパティを持ち、meta プロパティは任意のプロパティを持たせて使う想定です。

import "@tanstack/react-table";

declare module "@tanstack/table-core" {
  interface ColumnMeta<TData extends RowData, TValue> {
    rule: "unread" | "today";
  }
}

TypeScript と併用する場合、ColumnMeta の型定義を拡張しておくと便利です。 今回は rule というプロパティを meta に持たせます。

Cell で meta プロパティから受け取る

export const FlagCell = (props: Props): ReactElement => {
  props.column.columnDef.meta?.rule
};

Cell の props.column.columnDef から column に指定したプロパティを取得できます。 meta も column に指定したプロパティです。

実装

const isFlaged = ({
  row: { original },
  column: {
    columnDef: { meta },
  },
}: Props): boolean => {
  switch (meta?.rule) {
    case "unread":
      return original.unread > 0;
    case "today":
      return isToday(original.timestamp);
    default:
      throw new Error();
  }
};

export const FlagCell = (props: Props): ReactElement => {
  if (isFlaged(props)) {
    return <Cell>🚩</Cell>;
  }
  return <Cell> </Cell>;
};

ソースの説明です。meta.rule で適用する判定ルールを切り替えます。original にアクセスすることで各列のセルの値を取得できます。詳しくは前回の記事で述べています。

  columnHelper.accessor("id", {
    header: "フラグ",
    cell: FlagCell,
    meta: { rule: "today" },
  }),

呼び出し側は、このようになります。meta.rule に 判定ルールを渡します。

おわりに

accesor"id" を渡していますが、これは Cell 内で未使用です。(なので他の column名を渡しても同じです)この部分は改良の余地があります。

また、React Table での meta の使用は便利ではあるのですが、あまり多用すると複雑になるので、セルの機能が明確に別とみなせる場合は、新しくセルを作る方がわかりやすい運用になると考えます。

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

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

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

求人応募してみる!

投稿者 Chaki Hironori

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