Reactのmaterial-tableで外部APIを利用している場合のソート実装でやったこと


目的

Reactのmaterial-tableで、dataに外部APIを利用している場合のソート実装とスタイル調整の覚書です

バージョン

下記バージョンで確認しました

  • React 17.0
  • material-table 1.69.2
  • material-ui-core 4.11.3
  • lodash 4.17.21

公式サンプル

データに外部APIを利用する方法は 公式のRemote Data Previewの通りですが、公式サンプルではソートが出来ません。
これは、変更があるたびに新しいquery objectで関数が呼ばれるのですが、呼び出しているAPI reqres.in でソートに対応していないからです。

ソートの実装方法

ソートするとデータ変更が走り queryorderByorderDirection が連携されるので、これを利用してソートを実装します。

案1 APIでソートに対応する

リクエストパラメータで指定された項目、並び順でソートしてレスポンスを返すAPIを作成し、UIから呼び出す方法です

UIからAPIに連携するパラメータ

ページングするので、ソート情報と合わせてページング情報もAPIに連携します。
query.pageSizequery.page はoptionsでページングを利用しない設定をしない場合でも存在するので必須とみなして良いでしょう。
初期表示時など query.orderByquery.sortDirection が存在しない場合はAPIのリクエストパラメータに含める必要はありません。

下記リクエストパラメータをAPIに連携すれば良いと思いますが、実際の要件によるので確認してください。

  • ページング情報:必須
    • 1ページあたりの件数 (query.pageSize )
    • 現在何ページか (query.page + 1)
  • ソート情報:任意
    • ソートする項目 (query.orderBy.field)
    • ソート順 (query.orderDirection)

APIでの対応

UI側からのリクエストパラメータを受け付ける

セキュリティ対策で、リクエストを受け付けた後はバリデーションを行いましょう。

データ検索処理

連携されたリクエストパラメータを利用して、データの検索を行います。
動的SQLでページング、ソートを行うことになるでしょう。
ソートする項目はUI上のフィールド名のため、データベースのカラム名とUI上のフィールド名の変換を持つ必要があるかもしれません。

APIレスポンスの作成と返却

公式のUsageに従い下記をレスポンスで返却します。JSONが便利です。
https://material-table.com/#/docs/features/remote-data

  • 検索結果
    • material-tableの columns で指定するフィールドが必要です
  • テーブルに表示する全レコード件数
    • ページング、ソート有無関係ない、テーブルの全件数です
    • ページングする場合、何件中何件の形で表示されるため必要です
  • 現在のページ数

案2 API返却結果をUI側でソートする

API仕様上ソート結果を反映できない場合は、lodashなどを使って result.data をソートします。

初期表示時など query.orderByquery.sortDirection が存在しない場合は、ソートせず result.data をそのままdataに設定します。

おまけ:スタイルの調整

hover,activeの色の変更

スタイル次第でこのように、項目をクリックしてソートした後に文字が見えない状態になることがあります。

  • hoverしたときは背景とほぼ同じ色が利用される
  • ソート後にマウスを項目から離した後も、MuiTableSortLabel-active の背景色が黒 のが理由なので、Material UIのテーマをオーバライドして MuiTableSortLabel のスタイルを付けます。
  const theme = createMuiTheme({
    overrides: {
      MuiTableSortLabel: {
        root: {
          color: "#fff",
          "&:hover": {
            color: "#fff !important"
          }
        },
        active: {
          color: "#fff !important"
        }
      }
    }
  });

ここではとりあえず表示させたいので !important を付けて優先順位をあげましたが、StackOverflowの2件目の回答『Solution for your problem is following:』も良さそうです。

ソートアイコンのカスタマイズ

ソートアイコンのサイズが大きい、背景色やスタイルによってはソート操作後にアイコンが見にくい、といった時はカスタマイズできます。
DevelopersIOさんのこちらの記事の通りです。

動作サンプル

CodeSandboxのサンプルです。このページの説明の『案2 API返却結果をUI側でソートする』と『スタイルの調整』を実装しています。
修正していろいろな挙動を試してみてください。
https://codesandbox.io/s/material-table-remote-data-sort-demo-vgfhm?file=/src/App.js

参考