mui-datatablesを使って高機能なテーブルを作ろう！

## 実現したいこと
検索機能やソート機能、フィルター機能がついてる高機能なテーブルを作る。
具体的にはmui-datatablesの標準機能から選択された際や項目をクリックされた際にダイアログを出すなど独自機能を追加する。

## 使うライブラリ
 - mui-datatables
 - @mui/material

## 完成形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/861182/fdaf0102-1142-7bc8-0b6d-98f2603fe453.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/861182/54c551f9-4122-f753-4ed0-7bb575b69cb9.png)

### サンプルコード
```typescript
const columns = [
    {
        name: "personalId",
        label: "ID",
        options: {filter: false, display: false}
    },
    {
        name: "name",
        label: "ポケモン名",
        options: {
            filter: true,
            sort: true,
        }
    },
    {
        name: "tag",
        label: "タグ",
        options: {
            filter: true,
            sort: true,
            customBodyRenderLite: (dataIndex: number) => {
                return (
                    <>
                    // onClickだと引数が取れないので引数を取らない無名関数の中で
                    // 引数を取った関数を呼び出す。
                        <div onClick={() => openTagEdit(dataIndex)}>
                            {props.pokemons[dataIndex].tag.map(tag => 
                                <Button variant="outlined" key={tag}>{tag}</Button>)}
                            {props.pokemons[dataIndex].tag.length == 0 &&
                                <Button variant="outlined">タグを追加</Button>}
                        </div>
                    </>
                )
            },
        }
    },
    // 中略
    {
        name: "nature",
        label: "性格",
        options: {
            filter: true,
            sort: true,
            customBodyRenderLite: (dataIndex: number) => {
                return (
                    <>
                        <div onClick={() => openNatureEdit(dataIndex)}>
                            {props.pokemons[dataIndex].nature}
                        </div>
                    </>
                )
            },
        }
    },
]
```
```typescript
const options = {
    sortOrder: {name: "personalId" as any, direction: "asc" as any},
    customToolbarSelect: (selectedRow: any, displayData: any) =>
        (
            <GrownPokemonTableSelectMenu 
                displayData={displayData} 
                selectedRows={selectedRow}/>
        )
}
```
```typescript
<MUIDataTable
    title={""}
    data={props.pokemons}
    columns={columns}
    options={options}
/>
```

## 解説
### テーブル内の指定の項目をクリックした時に専用のダイアログを表示する方法
この場合ではポケモンの性格部分をクリックした時にそのポケモンの性格を編集するダイアログを表示させたいです。
そのためにはカラム設定でcustomBodyRenderLiteというオプションをいれます。これはカラムの表示内容を任意の物にできるオプションです。引数としてデータの序数を取るので具体的な番号で表示内容を変えたり(例えば偶数番目と奇数番目で表示内容を変える)、その行ごとに処理を行う事が可能です。
ここで注意しなくてはいけないのは通常の表示部分も上書きされてしまうので表示内容を表示させる事を忘れないようにしましょう。

### 行を選択したときに表示されるボタンをカスタムする方法。
デフォルトではこのテーブル上から行を削除するボタンしか行を選択したときのメニューにありませんが実際はそれだけで済むことは少ないと思います。というか削除機能だってそれをAPI叩いてバックエンドに反映させたいとかあると思います。
そういう時にカスタムされた内容を表示するためにはテーブル自体のoptionsにcustomToolbarSelectを追加します。
これはselectedRowとdisplayDataという二つの変数が使えます[^1]。この二つの変数についてselectedRowに関してはdataというプロパティに表示されてる全てのテーブルの配列が入っています。例えば以下の通りで取り出せます。
```typescript
// 1行目の内容の配列を取り出す
displayData.filter((x: { dataIndex: number; }) => x.dataIndex == 1)
// 1行目の2列目の内容を取り出す
displayData.filter((x: { dataIndex: number; }) => x.dataIndex == 1)
    .map((x: { data: any[]; }) => x.data[2])
```
次にselectedRowです。これから選択されている行のdataIndexの配列を抜くコードは以下の通りです。
```typescript
selectedRows.data.map((x: { dataIndex: number; }) => x.dataIndex)
```
あとはこれらの情報を元によしなに使っていきましょう。

## 最後に
余談ですがポケモンの構築情報を管理できるサービスを作っています。今回のサンプルコードもこちらから取ってきました。
現在公開されている部分では1つの構築にポケモンを追加したり削除したり編集したりするメモ程度の機能しかありませんがこれからどんどん機能を追加する予定です。手始めにいまのサンプルコード部分にもなりますが以下の機能の追加を考えています。
 - 複数構築の管理
 - 育成済みポケモンの管理(ここから構築にまとめて突っ込む事も可能です)
 - S調整機能(スライダーで努力値を動かすとその努力値で準速/最速〇族が抜けるのかが表示されます)
 
これらは一応機能自体の実装は終わり細かいバグ調整中ですのでデプロイはもうしばらくお待ちください。ポケモン対戦をやってる方がいれば良かったら覗いて見てください。
URL：https://pokebuild.sasakirione.com

## 参考文献
 - [mui-datatablesのリポジトリ](https://github.com/gregnb/mui-datatables)(readmeがドキュメントになっています)
 - [MUIでDataTablesを使ってみる（Next.js,TypeScript)](https://zenn.dev/furai_mountain/articles/488897d08a8975)



[^1]: ここでは型付けサボってany型にしていますがそこは見逃してください。