React + json-server + ag-Grid で色々と試してみた ［ag-Grid基礎編］

# はじめに
この記事は、[前回記事](https://qiita.com/potstickers/items/5ca331b939a8bb2056cf) の続編です。環境周りの情報や、モック API の作成方法はそちらに記載していますので、お時間のある方は併せて読んで頂けると嬉しいです。

フロントエンドの構築には React と Material-UI を使っていますが、この記事の目的は ag-Grid の機能や実装方法を紹介することなので、ここでは取り扱いません。また、掲載しているソースコードは、説明を分かりやすくするために直接的な関係がない部分を思い切って省略しているのでご注意ください。

それでは行ってみましょう！

# テーブル定義
うーん、実にシンプルですね。`div` で `AgGridReact` を囲うだけです。ag-Grid のテーマは `div` の `className` 属性で指定します。このとき指定したテーマの css を一緒に import しておくのがポイントです。標準でいくつかのテーマが提供されているので [ここ](https://www.ag-grid.com/documentation/react/themes-provided/) を参考にしてください。

```react
import { AgGridReact } from "ag-grid-react";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css"; // ← ポイント！

const AgGrid = () => {
  return (
    <div className="ag-theme-alpine" style={{ height: "100%", width: "100%" }}>
      <AgGridReact
        // プロパティを設定
        domLayout={"autoHeight"}  // テーブルの高さを自動調整
      />
    </div>
  );
};
```

# 列定義
次に、列定義を見ていきましょう。基本は `columnDef` に１列ずつ定義をしていきます。ただ、この方法だと列数が多くなった場合に管理が煩雑になるのは目に見えてますね。例えば、全列に検索フィルタを付けたいとか、数値系の項目は右寄せしたいとか…。考えただけでもゾッとします。

そういったときに便利なのが `columnTypes` と `defaultColDef` です。columnTypes は同種の列に対して、defaultColDef は全ての列に対して共通の設定を適用することができます。

そして、定義は `columnDef` > `columnTypes` > `defaultColDef` の順で優先されるので、適切なレベルで設定を行うことで、定義を減らしメンテナンス性を上げることができます。

ちなみに、columnTypes には `rightAligned` という右寄せの定義が標準で用意されているので、自分でわざわざ定義をする必要はありません。なかなか気が利いていますね！

列定義に関しては [ここ](https://www.ag-grid.com/documentation/vue/column-definitions/) や Columns セクション下の関連ドキュメントを見てもらうと、さらに色々な事が分かると思います。

```react
const AgGrid = () => {

  // 全列に共通の定義
  const defaultColDef = {
    sortable: true,  // ソート可
    editable: true,  // 編集可
  };

  // 列タイプの定義
  const columnTypes = {
    nonEditableColumn: { editable: false },  // 編集不可
  };

  // 個別列の定義
  const columnDefs = [
    {
      headerName: "Group", // 列のグルーピング
      children: [
        {
          headerName: "Column1",
          field: "col1",
          type: "nonEditableColumn", // 編集不可が優先
        },
        {
          headerName: "Column2",
          field: "col2",
          type: "rightAligned", // 右寄せ
          sortable: false, // ソート不可が優先
        },
      ],
    },
    {
      headerName: "Column3",
      field: "col3",
    },
  ];

  return (
    <div className="ag-theme-alpine" style={{ height: "100%", width: "100%" }}>
      <AgGridReact
        // それぞれの定義を指定
        defaultColDef={defaultColDef}
        columnTypes={columnTypes}
        columnDefs={columnDefs}
      />
    </div>
  );
};
```

# データ反映

データの反映にはいくつかの方法がありますが、ここでは Grid API を使った方法を試していきます。Grid API は `onGridReady` のコールバック関数として渡される Grid オブジェクトからアクセスできます。

今回は [前回](https://qiita.com/potstickers/items/5ca331b939a8bb2056cf) 作った REST API から取得したデータをテーブルに反映したいので、`applyTransaction` メソッドを使用します。この引数に取得したデータを渡すのですが、データを `add` プロパティに設定するところがポイントです。他にも `update` や `remove` プロパティーがあるのですが、何が起こるかは何となく想像できますよね。

Grid API にも様々な API が定義されているので、詳しくは [ここ](https://www.ag-grid.com/documentation/react/grid-api/) を見てください。

```jsx
const AgGrid = () => {
    
  // ag-Grid の準備完了後に呼ばれるコールバック関数
  const onGridReady = (grid) => {
    (async () => {
      grid.api.applyTransaction({ add: await getData() });  // データを追加
    })();
  };

  // REST API からデータを取得
  const getData = async () => {
    let { data } = await axios.get("http://localhost:3001/users");
    return data;
  };

  return (
    <div className="ag-theme-alpine" style={{ height: "100%", width: "100%" }}>
      <AgGridReact
        // コールバック関数を指定
        onGridReady={onGridReady}
      />
    </div>
  );
};
```

`applyTransaction` に渡すデータはこんなイメージです。データと列のマッピングは [列定義](#列定義) で行った `field` の指定によって行われます。

```json
[
  {
    "col1": "value0-1",
    "col2": "value0-2",
    "col3": "value0-3"
  },
  {
    "col1": "value1-1",
    "col2": "value1-2",
    "col3": "value1-3"
  }
]
```
# 動作確認
ここまでの内容を組み合わせると下のような画面が完成します。各列の状態と併せて確認してみて下さい。

* Column1 : 編集不可 / ソート可
* Column2 : 編集可能 / ソート不可 / 右寄せ
* Column3 : 編集可能 / ソート可

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1036913/740edad0-48d8-e0b3-6463-b6768866415b.png)

<details><summary>完成ソースコード</summary><div>

```jsx
import { AgGridReact } from "ag-grid-react";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css"; // ← ポイント！
import axios from "axios";
import { Grid } from "@material-ui/core";

const AgGrid = () => {

  // ag-Grid の準備完了後に呼ばれるコールバック関数
  const onGridReady = (grid) => {
    (async () => {
      grid.api.applyTransaction({ add: await getData() }); // データを追加
    })();
  };

  // REST API からデータを取得
  const getData = async () => {
    let { data } = await axios.get("http://localhost:3001/samples");
    return data;
  };

  // 全列に共通の定義
  const defaultColDef = {
    sortable: true, // ソート可
    editable: true, // 編集可
  };

  // 列タイプの定義
  const columnTypes = {
    nonEditableColumn: { editable: false }, // 編集不可
  };

  // 個別列の定義
  const columnDefs = [
    {
      headerName: "Group", // 列のグルーピング
      children: [
        {
          headerName: "Column1",
          field: "col1",
          type: "nonEditableColumn", // 編集不可が優先
        },
        {
          headerName: "Column2",
          field: "col2",
          type: "rightAligned", // 右寄せ
          sortable: false, // ソート不可が優先
        },
      ],
    },
    {
      headerName: "Column3",
      field: "col3",
    },
  ];

  return (
    <>
      <Grid container spacing={1}>
        <Grid item xs={12}>
          <div
            className="ag-theme-alpine"
            style={{ height: "100%", width: "100%" }}
          >
            <AgGridReact
              defaultColDef={defaultColDef}
              columnTypes={columnTypes}
              columnDefs={columnDefs}
              onGridReady={onGridReady}
              domLayout={"autoHeight"}
            />
          </div>
        </Grid>
      </Grid>
    </>
  );
};

export default AgGrid;
```
</div></details>

# まとめ
定義する列数や複雑さにもよりますが、わずか数十行のコードで REST API からのデータ反映に加え、機能と見栄えを両立したテーブルが作成できました。また、Reactでコンポーネント化がされているのでコードの理解もしやすいです。

API ドキュメントなどを読みながら実装を進めたので、実際にはそこそこ時間がかかってしまったのですが、一度理解すればこの程度の画面は数時間で実装できると思います。

次回は応用編と位置づけて、もう少し深堀りして色々な機能を紹介していきたいと思います！
（例によって、長くなったので分割させてください🙏）

# 参考リンク
* [ag-Grid 公式ドキュメント](https://www.ag-grid.com/documentation/react/)
* [React 公式ドキュメント](https://ja.reactjs.org/docs/getting-started.html)
* [Material-UI 公式ドキュメント](https://material-ui.com/)
* [axios GitHub](https://github.com/axios/axios)