はじめに
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を参考にテーブルを作成します。
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
特にスタイリングしていない、データが並べられただけのテーブルができます。
これでhooksを使ってテーブルを作成することができました。
見た目をv6っぽくしていく
cssの適用にstyled-componentsを利用します。
設計用にとりあえず Div
コンポーネントを作っておきます。
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>
要素のスタイルを作ります。
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
で縦に表示させているようです。
何故このような実装になっているかはよくわかっていませんが、とりあえず真似ておきます。
見た目に大きな変化はありませんが、少しシュッとした気がします。
thead
ヘッダー部分をスタイリングします。
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
で透明度を指定して調整します。
ヘッダー部分がそれっぽくなりました。
tbody
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
クラスを適用したものにしました。
これでシンプルなテーブルが完成しました。
感想
今回はbasicなテーブルを作りましたが、ほとんどのケースではpaginationやsortなどの機能が必要不可欠かと思います。
ですがほとんどの場合、hooksで機能作成 ⇒ cssで見た目を整える、という流れは変わらないと思います。
また、見ての通りやることはシンプルですが、v6からそのままアップグレードしようとすると修正量が多いため、実運用でやるのはあまり現実的ではないかなと感じました。
react-table-6
というパッケージが提供されているみたいなので、それを使ってv7と共存させる形が良さそうです。