ReactApps

2019年4月15日

編集可能なテーブルをつくる

okkynzj40

はじめに

ローカル環境でこのサンプルを動かすには以下の手順に従ってください。

$ git close git@github.com:reiwa/reactapps.git
$ cd reactapps
$ yarn
$ yarn workspace table start

※ $の部分はペーストしないでください。

内容

ユーザが入力して編集が可能なテーブルをつくります。
基本情報などカラムが2つほどのデータをテーブルで編集することが出来ます。

コード

import React, { ChangeEvent, FunctionComponent, useState } from 'react'

const App: FunctionComponent = () => {
  const [cells, setCells] = useState([
    { code: 'zh', name: 'Chinese', nameJa: '中国語' },
    { code: 'ru', name: 'Russian', nameJa: 'ロシア語' },
    { code: 'en', name: 'English', nameJa: '英語' },
  ])

  const onChangeCell = (index: number, key: string) => (
    event: ChangeEvent<HTMLInputElement>
  ) => {
    const _cells = [...cells]
    _cells[index] = { ..._cells[index], [key]: event.target.value }
    setCells(_cells)
  }

  return (
    <table>
      <thead>
        <tr>
          <td>{'code'}</td>
          <td>{'name'}</td>
          <td>{'nameJa'}</td>
        </tr>
      </thead>
      <tbody>
        {cells.map((cell, i) => (
          <tr key={i}>
            <td>
              <input onChange={onChangeCell(i, 'code')} value={cell.code} />
            </td>
            <td>
              <input onChange={onChangeCell(i, 'name')} value={cell.name} />
            </td>
            <td>
              <input onChange={onChangeCell(i, 'nameJa')} value={cell.nameJa} />
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}

export default App

いくつかポイント

テーブルの行は配列で表現できます。コンポーネントはこれを状態として扱います。

const [cells, setCells] = useState([
  { code: 'zh', name: 'Chinese', nameJa: '中国語' },
  { code: 'ru', name: 'Russian', nameJa: 'ロシア語' },
  { code: 'en', name: 'English', nameJa: '英語' }
])

index(行数)とkey(行)からセルを更新します。この関数は関数を返します。

const onChangeCell = (index: number, key: string) => (
  event: ChangeEvent<HTMLInputElement>
) => {
  const _cells = [...cells]
  _cells[index] = { ..._cells[index], [key]: event.target.value }
  setCells(_cells)
}

スプレッド演算子を用いて新しいオブジェクトを生成します。

_cells[index] = { ..._cells[index], [key]: event.target.value }

keyには入力で変化しない値を使用してください。keyの値が変更されるとDOMが再生成され入力がフォーカスが外れます。

<tbody>
  {cells.map((cell, i) => <tr key={i} />}
</tbody>

例えば以下はkeyの値が変わるのでダメです。

<tbody>
  {cells.map((cell, i) => <tr key={cell.code} />}
</tbody>