4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【react-table】v7のhooksを使ってv6のテーブルっぽいものを作る

Posted at

はじめに

react-table v7のアルファ版がリリースされてから1年以上経過しましたが、ついにv7が正式にリリースされましたね。
v6を使っている方で、アップグレードを検討している方もいるのではないでしょうか。

これまでは、色々な機能を持つテーブルコンポーネントをインポートして利用する形でした。
v7では、ビューとロジックが完全に分離され、ライブラリ側は各種テーブル機能を持つhooksのみを提供するようになります。

アップグレードにより使い方が大きく変わり、テーブルコンポーネント自体は自分で作る必要があります。
v6のテーブルコンポーネントだけ提供されてないかな?と思って探してみたのですが、なさそうだったので自分で作ってみました。

環境

  • react 16.12
  • react-table 7.0.0
  • styled-components 5.0.1

シンプルなテーブルを作る

データを表示するだけの簡単なテーブルを作成します。

基本的には、hooksを使ってテーブルを作成し、cssで見た目を整えていく流れになります。

以下のコード内で使用している makeData は、 サンプル等を参考にして適宜配置してください。

hooksを使ってテーブルを作る

v7のBasic Sampleを参考にテーブルを作成します。

App.jsx
import React from 'react'
import { useTable } from 'react-table'
import { makeData } from './utils'

const Table = ({ columns, data }) => {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable({
    columns,
    data,
  })

  return (
    <table {...getTableProps()}>
      <thead>
        {headerGroups.map(headerGroup => (
          <tr {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map(column => (
              <th {...column.getHeaderProps()}>{column.render('Header')}</th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody {...getTableBodyProps()}>
        {rows.map((row, i) => {
          prepareRow(row)

          return (
            <tr {...row.getRowProps()}>
              {row.cells.map(cell => {
                return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
              })}
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}

const App = () => {
  const columns = [
    // 長いので省略
  ]

  const data = React.useMemo(() => makeData(20), [])

  return (
    <Table columns={columns} data={data} />
  )
}

export default App

特にスタイリングしていない、データが並べられただけのテーブルができます。

image.png

これでhooksを使ってテーブルを作成することができました。

見た目をv6っぽくしていく

cssの適用にstyled-componentsを利用します。
設計用にとりあえず Div コンポーネントを作っておきます。

App.jsx
import React from 'react'
import { useTable } from 'react-table'
import styled from 'styled-components'
import { makeData } from './utils'

const Div = styled.div`
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(0, 0, 0, 0.1);
`

// ...

const App = () => {
  // ...

  return (
    <Div>
      <Table columns={columns} data={data} />
    </Div>
  )
}

以降はv6のソースコード(主に index.styl )を参考にスタイリングしていきます。

table

<table> 要素のスタイルを作ります。

App.jsx
const Div = styled.div`
  // ...

  table {
    flex: auto 1;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    border-collapse: collapse;
    overflow: auto;
  }
`

ソースによると、table要素をフレックスボックスにして flex-direction: column で縦に表示させているようです。

何故このような実装になっているかはよくわかっていませんが、とりあえず真似ておきます。

image.png

見た目に大きな変化はありませんが、少しシュッとした気がします。

thead

ヘッダー部分をスタイリングします。

App.jsx
const Div = styled.div`
  // ...

  table {
    // ...

    thead {
      flex: 1 0 auto;
      display: flex;
      flex-direction: column;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
      box-shadow: 0 2px 15px 0px rgba(0, 0, 0, 0.15);

      tr {
        flex: 1 0 auto;
        display: inline-flex;

        :not(:last-child) {
          background: rgba(0, 0, 0, 0.03);
          border-bottom: 1px solid rgba(0, 0, 0, 0.05);
        }

        th {
          flex: 1 0 0px;
          white-space: nowrap;
          text-overflow: ellipsis;
          overflow: hidden;
          padding: 5px 5px;
          line-height: normal;
          position: relative;
          border-right: 1px solid rgba(0, 0, 0, 0.05);
          transition: box-shadow .3s cubic-bezier(0.175,  0.885, 0.320, 1.275);
          box-shadow: inset 0 0 0 0 transparent;
        }
      }
    }
  }
`

疑似要素を使って HeaderGroup にも対応できるようにします。

線や背景の色は rgba で透明度を指定して調整します。

image.png

ヘッダー部分がそれっぽくなりました。

tbody

App.jsx
const Div = styled.div`
  // ...

  table {
    // ...

    tbody {
      flex: 99999 1 auto;
      display: flex;
      flex-direction: column;
      overflow: auto;

      tr {
        flex: 1 0 auto;
        display: inline-flex;

        :not(:last-child) {
          border-bottom: solid 1px rgba(0, 0, 0, 0.05);
        }

        // -striped
        :nth-child(odd) {
          background: rgba(0, 0, 0, 0.03);
        }

        // -highlight
        :hover {
          background: rgba(0, 0, 0, 0.05);
        }

        td {
          flex: 1 0 0px;
          white-space: nowrap;
          text-overflow: ellipsis;
          padding: 7px 5px;
          overflow: hidden;
          transition: .3s ease;
          transition-property: width, min-width, padding, opacity;

          :not(:last-child) {
            border-right: 1px solid rgba(0, 0, 0, 0.02);
          }
        }
      }
    }
  }
`

今回は -striped-highlight クラスを適用したものにしました。

image.png

これでシンプルなテーブルが完成しました。

感想

今回はbasicなテーブルを作りましたが、ほとんどのケースではpaginationやsortなどの機能が必要不可欠かと思います。

ですがほとんどの場合、hooksで機能作成 ⇒ cssで見た目を整える、という流れは変わらないと思います。

また、見ての通りやることはシンプルですが、v6からそのままアップグレードしようとすると修正量が多いため、実運用でやるのはあまり現実的ではないかなと感じました。

react-table-6 というパッケージが提供されているみたいなので、それを使ってv7と共存させる形が良さそうです。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?