kintone UI ComponentのテーブルをHooksで記述する

テーブルの取り扱いで少し戸惑ったのでメモします。

[こちらのClass形式で書かれたサンプル](https://kintone.github.io/kintone-ui-component/latest/Reference/Table/)をHooksに書き直します。

# Class形式

リンク先に記載されていますがこちらにもコピーしておきます。

```javascript
import React from "react";
import { render } from "react-dom";
import { Table, Text } from "@kintone/kintone-ui-component";

class Plugin extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      tableData: [{ text: "this is a text field" }],
      defaultRowData: { text: "default text field value" }
    };
  }

  handleRowAdd = ({ data }) => {
    this.setState({ tableData: data });
  };

  handleRowRemove = ({ data }) => {
    this.setState({ tableData: data });
  };

  handleCellChange = ({ data }) => {
    this.setState({ tableData: data });
  };

  render() {
    const { tableData, defaultRowData } = this.state;
    const columns = [
      {
        header: "Text",
        cell: ({ rowIndex, onCellChange }) => {
          return (
            <Text
              value={tableData[rowIndex].text}
              onChange={newValue =>
                onCellChange(newValue, tableData, rowIndex, "text")
              }
            />
          );
        }
      }
    ];

    return (
      <Table
        columns={columns}
        data={this.state.tableData}
        defaultRowData={defaultRowData}
        onRowAdd={this.handleRowAdd}
        onRowRemove={this.handleRowRemove}
        onCellChange={this.handleCellChange}
        actionButtonsShown={true}
        isVisible={true}
      />
    );
  }
}

render(<Plugin />, document.querySelector("#root"));
```

# Hooks形式

```javascript
import React, { useState } from "react";
import { render } from "react-dom";
import { Table, Text } from "@kintone/kintone-ui-component";

const Plugin = () => {
  const [table, setTable] = useState({
    tableData: [{ text: "this is a text field" }],
    defaultRowData: { text: "default text field value" }
  });

  const handleRowAdd = ({ data }) => {
    setTable(prev => {
      return { ...prev, tableData: data };
    });
  };

  const handleRowRemove = ({ data }) => {
    setTable(prev => {
      return { ...prev, tableData: data };
    });
  };

  const handleCellChange = ({ data }) => {
    setTable(prev => {
      return { ...prev, tableData: data };
    });
  };

  const columns = [
    {
      header: "Text",
      cell: ({ rowIndex, onCellChange }) => {
        return (
          <Text
            value={table.tableData[rowIndex].text}
            onChange={newValue =>
              onCellChange(newValue, table.tableData, rowIndex, "text")
            }
          />
        );
      }
    }
  ];

  return (
    <Table
      columns={columns}
      data={table.tableData}
      defaultRowData={table.defaultRowData}
      onRowAdd={handleRowAdd}
      onRowRemove={handleRowRemove}
      onCellChange={handleCellChange}
      actionButtonsShown={true}
      isVisible={true}
    />
  );
};
render(<Plugin />, document.querySelector("#root"));
```

## ポイント
### Hooks形式ではstateはマージされない
```javascript
setTable({ tableData: data })
```
このように書くと、プロパティ「defaultRowData」なしで上書きされてしまうので以下のエラーが発生する。

> Warning: A component is changing a controlled input of type text to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components