0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React × Mantineでテーブルを扱う方法

Posted at

1. テーブルコンポーネントの種類

Reactテーブル関連コンポーネントとして、主に3種類が存在します。

1. Table (@mantine/core)

  • 概要: Mantineのコアライブラリに含まれる基本的なテーブルコンポーネント。シンプルなデータ表示に適し、テーマスタイル(例: ダークモード対応)が自動適用されます。
  • 主な特徴:
    • Sticky header(固定ヘッダー)、ストライプ行、ホバー効果、スクロールコンテナ。
    • データpropで自動行生成可能。
    • 行選択(チェックボックス)や垂直レイアウト対応。
  • 使いどころ: 軽量で基本的なテーブルが必要な場合。高度な機能(ソート、フィルタリング)は手動実装。
  • インストール: @mantine/core をインストール(標準)。

2. DataTable (@mantine/datatable)

  • 概要: Mantineの拡張パッケージで、データリッチなアプリケーション向けのテーブル。軽量で依存関係なし、Mantine V8対応。
  • 主な特徴:
    • ソート、ページネーション、行選択(Gmail風のバッチ選択)、ダークモードサポート。
    • 非同期データロードやカスタムセルレンダリング。
  • 違い: 基本Tableよりデータグリッドのような機能が追加され、UIが洗練。データ量が多い場合に便利だが、TanStackベースではないためシンプル。
  • 使いどころ: 中規模のデータテーブルで、軽量さを重視する場合。
  • インストール: npm install @mantine/datatable

3. Mantine React Table

  • 概要: TanStack React TableをMantineスタイルでラップした独立ライブラリ(KevinVandy/mantine-react-table)。Mantine V7/V8対応(V2でV8サポート)。
  • 主な特徴:
    • 高度な機能: ソート、フィルタリング、ページネーション、行編集/作成、列リサイズ、行展開。
    • ユーザーfriendlyなUIとデフォルト設定。
  • 違い: 他の2つよりパワフルで、行編集などの先進機能あり。依存関係(TanStack Table)があるため、複雑なテーブルに最適。
  • 使いどころ: 大規模アプリやカスタム機能が必要な場合。
  • インストール: npm install mantine-react-table @mantine/core

例えば、シンプルならTable、データ操作ならDataTable、高度ならMantine React Tableを選択するのがいいです。2025年現在、Mantine 8.0リリース後もこれら3つが並存しています。

2. 基本の使い方

1. Table (@mantine/core)

シンプルなデータ表示に適し、テーマスタイルが自動適用されます。手動で行を作成するか、data propで自動生成できます。主な特徴は、sticky header、ストライプ行、ホバー効果、スクロール対応です。

  • 手動行作成例: データ配列をmapして行を作成。
    import { Table } from '@mantine/core';
    
    const elements = [
      { position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' },
      { position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' },
      // 他のデータ
    ];
    
    function BasicTable() {
      const rows = elements.map((element) => (
        <Table.Tr key={element.name}>
          <Table.Td>{element.position}</Table.Td>
          <Table.Td>{element.name}</Table.Td>
          <Table.Td>{element.symbol}</Table.Td>
          <Table.Td>{element.mass}</Table.Td>
        </Table.Tr>
      ));
    
      return (
        <Table>
          <Table.Thead>
            <Table.Tr>
              <Table.Th>Position</Table.Th>
              <Table.Th>Name</Table.Th>
              <Table.Th>Symbol</Table.Th>
              <Table.Th>Mass</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>{rows}</Table.Tbody>
        </Table>
      );
    }
    
  • data prop使用例: オブジェクトで自動生成。
    import { Table } from '@mantine/core';
    
    const tableData = {
      caption: 'Elements',
      head: ['Position', 'Name', 'Symbol', 'Mass'],
      body: [
        [6, 'Carbon', 'C', 12.011],
        [7, 'Nitrogen', 'N', 14.007],
      ],
    };
    
    function AutoTable() {
      return <Table data={tableData} />;
    }
    
  • キーpropと説明:
    • stickyHeader: true - ヘッダーを固定。
    • horizontalSpacing: 'md' - セルパディング調整。
    • withTableBorder: true - テーブルボーダー追加。
    • captionSide: 'bottom' - キャプション位置。

2. DataTable (@mantine/datatable)

DataTableは拡張パッケージで、データリッチなテーブル向け。recordsとcolumnsを設定するだけで、ソートやページネーションが使えます。主な特徴は、軽量、非同期ロード対応、行選択、列スタイリング。

  • 基本例: records(データ配列)とcolumns(列定義)を指定。
    import { DataTable } from 'mantine-datatable';
    
    const companies = [
      { id: 1, name: 'Company A', city: 'Tokyo', employees: 100 },
      { id: 2, name: 'Company B', city: 'Osaka', employees: 200 },
      // 他のデータ
    ];
    
    function BasicDataTable() {
      return (
        <DataTable
          records={companies}
          columns={[
            { accessor: 'name', title: 'Company Name' },
            { accessor: 'city', title: 'City' },
            { accessor: 'employees', title: 'Employees', sortable: true },
          ]}
          withTableBorder
        />
      );
    }
    
  • ソート・ページネーション追加例: stateで管理。
    import { DataTable } from 'mantine-datatable';
    import { useState } from 'react';
    
    function SortedDataTable({ records }) {
      const [sortStatus, setSortStatus] = useState({ columnAccessor: 'employees', direction: 'asc' });
    
      return (
        <DataTable
          records={records}
          columns={[
            { accessor: 'name', title: 'Name' },
            { accessor: 'employees', title: 'Employees', sortable: true },
          ]}
          sortStatus={sortStatus}
          onSortStatusChange={setSortStatus}
          totalRecords={records.length}
          recordsPerPage={10}
          page={1}
          onPageChange={(p) => console.log(p)}
        />
      );
    }
    
  • キーpropと説明:
    • records: データ配列(必須)。
    • columns: 列オブジェクト配列(accessorでキー指定、titleでヘッダー、sortable: trueでソート有効)。
    • withColumnBorders: true - 列ボーダー追加。
    • fetching: true - ロード中インジケーター表示。
      基本的にrecordsとcolumnsで即テーブル生成可能。

3. Mantine React Table

useMantineReactTableフックで設定し、ソート・フィルタリング・ページネーションがデフォルト有効。主な特徴は、列リサイズ、行選択、拡張性高く、大規模データ向け。

  • hook使用例: columnsとdataをuseMemoで定義。
    import { useMemo } from 'react';
    import { MantineReactTable, useMantineReactTable } from 'mantine-react-table';
    
    const data = [
      { firstName: 'John', lastName: 'Doe', city: 'Tokyo', age: 30 },
      { firstName: 'Jane', lastName: 'Smith', city: 'Osaka', age: 25 },
      // 他のデータ
    ];
    
    function BasicMRT() {
      const columns = useMemo(() => [
        { accessorKey: 'firstName', header: 'First Name' },
        { accessorKey: 'lastName', header: 'Last Name' },
        { accessorKey: 'city', header: 'City' },
        { accessorKey: 'age', header: 'Age' },
      ], []);
    
      const table = useMantineReactTable({
        columns,
        data,
        enableSorting: true,
        enablePagination: true,
      });
    
      return <MantineReactTable table={table} />;
    }
    
  • 直接prop例: hookなしでシンプルに。
    import { useMemo } from 'react';
    import { MantineReactTable } from 'mantine-react-table';
    
    // dataとcolumnsは上記と同じ
    
    function DirectMRT() {
      return <MantineReactTable columns={columns} data={data} />;
    }
    
  • キーpropと説明:
    • columns: 配列(accessorKeyでデータキー、headerでヘッダー)。
    • data: データ配列(安定したもの推奨)。
    • enableFiltering: true - フィルタリング有効(デフォルト)。
    • enableRowSelection: true - 行選択有効。

3.Mantineのテーブル機能比較表

機能・特徴 @mantine/core Table @mantine/datatable mantine-react-table
ソート 非対応(手動実装) 対応 対応
ページネーション 非対応 対応 対応
行選択(チェック) 非対応 対応 対応(柔軟に設定可能)
フィルタリング 非対応 非対応(手動で追加可能) 対応(標準機能)
行の編集・作成 非対応 非対応 対応
列のリサイズ 非対応 非対応 対応
必要な依存ライブラリ なし なし TanStack Table に依存
適している規模 小規模 中規模 大規模・複雑な要件に対応可能

4.各コンポーネントの制限・注意点

1. @mantine/coreTable コンポーネント

主な制限・注意点

項目 説明
data prop の柔軟性が低い data prop を使うと、ヘッダーとボディが固定構造になるため、カスタマイズ性が低い。複雑なセル(ボタン、リンク、条件分岐など)には不向き。
ソート・ページネーション非対応 自前でロジックを実装する必要がある。状態管理やUIの整備が必要。
行選択(チェックボックス)非対応 状態管理を含めて完全に手動実装が必要。複雑になりやすい。
レスポンシブ非対応 テーブル幅の自動調整や折り返しには自力でCSS対応が必要。
拡張性が限られる 本質的には静的なHTMLテーブルに近いため、インタラクティブな機能は追加しづらい。

使い方の注意点

  • UIが単純で、表示するだけの用途なら十分。
  • 複雑な操作をさせたい場合は他のテーブルに切り替えることを検討。

2. @mantine/datatable コンポーネント

主な制限・注意点

項目 説明
Mantine公式だが拡張的 Mantineの本体ではなく別パッケージ。メンテナンスの速度やIssue対応が若干遅れる傾向がある(GitHub上のIssue解決までに日数を要することも)。
カスタマイズ限界あり 独自の柔軟なカスタムUI(例:マルチセル内コンポーネント、動的な列追加など)はやや難しい。
フィルタリングは非対応 自前実装が必要。検索ボックスやセレクトなどのUIと状態管理を別で用意する必要がある。
拡張性は中程度 データを整えて渡すことで簡単に使えるが、複雑な挙動(編集・列ドラッグなど)には非対応。
タイピングはあるが簡易 TypeScript対応だが、型推論や列定義の柔軟性は限定的。大規模開発にはやや不足。

使い方の注意点

  • 管理画面などで「そこそこ複雑だけど、限界まで拡張しない」用途に向いている。
  • フィルタやリアルタイム更新が必要な場合は補助実装が必要。

3. mantine-react-tablemantine-react-table + @tanstack/react-table

主な制限・注意点

項目 説明
TanStack Table に依存 内部的に TanStack Table を使っており、そのバージョン(v8など)に強く依存するため、バージョンアップに伴う破壊的変更に注意が必要。
型定義が複雑 TypeScript環境で使う場合、columnsdata の型指定がやや煩雑。初心者には難しいこともある。
設定項目が非常に多い 柔軟にカスタマイズできる反面、初期設定のコード量が多くなりがち。使いこなすにはドキュメント熟読が必要。
パフォーマンスチューニング必要 仮想スクロールやデータ量が多いときに、useMemo や仮想化などの知識が求められる。
学習コストが高め 他の2つと比較して、概念やフック構成が複雑。習得に少し時間がかかる。

使い方の注意点

  • 柔軟で機能豊富な反面、構築・保守コストが上がる。
  • チーム内で共通の知識を持っておくことが大切。

5.TypeScriptで型安全に扱うための実例

1. @mantine/coreTable における型の使い方

基本的な考え方

  • Table は汎用的なテーブルなので、型安全な配列操作(map)で自前で制御します。
  • 型定義を作って、map時の補完やミス防止に活用。

実装例

type Element = {
  position: number;
  name: string;
  symbol: string;
  mass: number;
};

const elements: Element[] = [
  { position: 1, name: 'Hydrogen', symbol: 'H', mass: 1.008 },
  { position: 6, name: 'Carbon', symbol: 'C', mass: 12.011 },
];

function TypedTable() {
  const rows = elements.map((element) => (
    <Table.Tr key={element.name}>
      <Table.Td>{element.position}</Table.Td>
      <Table.Td>{element.name}</Table.Td>
      <Table.Td>{element.symbol}</Table.Td>
      <Table.Td>{element.mass}</Table.Td>
    </Table.Tr>
  ));

  return (
    <Table>
      <Table.Thead>
        <Table.Tr>
          <Table.Th>Position</Table.Th>
          <Table.Th>Name</Table.Th>
          <Table.Th>Symbol</Table.Th>
          <Table.Th>Mass</Table.Th>
        </Table.Tr>
      </Table.Thead>
      <Table.Tbody>{rows}</Table.Tbody>
    </Table>
  );
}

補足

  • Element 型を明示することで、キーや値のミスを防げます。
  • keyelement.name など、型の一意性も担保できます。

2. @mantine/datatable における型定義

ポイント

  • records 配列に型をつける。
  • columnsaccessor は文字列なので、型安全とは言えないが、as const + keyof を活用すればある程度安全性を確保できます。

型付き実装例

type Company = {
  id: number;
  name: string;
  city: string;
  employees: number;
};

const records: Company[] = [
  { id: 1, name: 'Company A', city: 'Tokyo', employees: 100 },
  { id: 2, name: 'Company B', city: 'Osaka', employees: 200 },
];

function CompanyTable() {
  return (
    <DataTable
      records={records}
      columns={[
        { accessor: 'name', title: 'Company Name' },
        { accessor: 'city', title: 'City' },
        { accessor: 'employees', title: 'Employees', sortable: true },
      ]}
    />
  );
}

補足

  • accessor: keyof Company とできないのが制約ですが、補完はある程度効きます。
  • より堅牢にしたい場合、accessorを "name" as const のように書くとミスが減ります。

3. mantine-react-table における型定義(本格的)

ポイント

  • columnsdata の両方に同じ型を適用する。
  • ジェネリクス(<T>)を明示すると型補完が強力に働きます。

型付き実装例(おすすめ構成)

import {
  MantineReactTable,
  MRT_ColumnDef,
  useMantineReactTable,
} from 'mantine-react-table';

type User = {
  firstName: string;
  lastName: string;
  age: number;
  email: string;
};

const data: User[] = [
  { firstName: 'John', lastName: 'Doe', age: 28, email: 'john@example.com' },
  { firstName: 'Jane', lastName: 'Smith', age: 34, email: 'jane@example.com' },
];

// columns の型を明示する
const columns: MRT_ColumnDef<User>[] = [
  { accessorKey: 'firstName', header: 'First Name' },
  { accessorKey: 'lastName', header: 'Last Name' },
  { accessorKey: 'age', header: 'Age' },
  { accessorKey: 'email', header: 'Email' },
];

function UserTable() {
  const table = useMantineReactTable<User>({
    columns,
    data,
    enableSorting: true,
    enablePagination: true,
  });

  return <MantineReactTable table={table} />;
}

補足

  • MRT_ColumnDef<User>[] のように型をつけることで、accessorKey に typo があるとコンパイルエラーになります。
  • より厳密に扱いたい場合は、useMemocolumns を囲むとパフォーマンスも向上します。

比較表

コンポーネント 型付け方法の例 型安全性 自動補完 コメント
@mantine/core Table 配列に型付け (type Row) すべて手動なので自由だが責任も伴う
@mantine/datatable records: 型[] accessor は string 扱いで注意が必要
mantine-react-table <T> に型定義、ColumnDef使用 タイポ防止・コンパイルでの型検査が強力
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?