React 表格指南和最佳 React 表格示例
关于 Flatlogic
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
本文将探讨 React 表格。顺便一提,别忘了看看我们之前关于 Bootstrap 表格的文章!为了保持文章简洁,我们不会过多赘述表格在现代 Web 开发中的重要性,也不会赘述不必要的细节。相反,我们将重点介绍如何选择 React 表格、开发过程中可能遇到的难点,以及其他能够真正帮助您创建出色实用 React 表格的实用技巧。此外,我们还为您准备了一份基于最流行的 React 表格库构建 React 表格的简要指南。
如何选择 React 表格库
为了选择合适的 React 表格,你需要确定它需要实现哪些功能。例如,你是否需要分页或排序。想想你需要哪些功能,然后选择符合这些需求的 React 表格库。
此外,还需要考虑是否愿意为库付费。付费版的 React 表格库提供了非常丰富的功能,可以帮助您进行开发。
现在让我们看看这在实际生活中是如何体现的:
- 如果您需要一个简单的页面,包含少量数据、自定义样式以及排序和筛选等最少的功能,我们建议使用 react-table;
- 如果你想要一个迷你版的 Google Sheets,可以使用 react-data-grid 或 react-datasheet;
- 如果您需要处理大量信息,我们建议使用 react – virtualize 或付费库,例如 Syncfusion 的 React 数据网格。
优秀 React Table 的特点
开发一个优秀的 React 表格是一项艰巨的挑战,你绝对应该经历这个过程。挑战在于,一个优秀的 React 表格必须同时满足多个要求——响应式设计、速度、可读性等等。让我们逐一仔细看看这些要求。
React表格必须具有响应式设计。
对于 React 数据表来说,在各种屏幕上正确显示至关重要。通常的做法是减小列宽并增加列长,但这并非总是能带来最佳用户体验。
React表格必须易于阅读
表格通常提供难以阅读、操作和编辑的信息。优秀的电子表格能够清晰易读、易于理解地展示信息,即使数据量达到成百上千行也是如此。灵活的 React 数据表解决方案可以处理长串数据,而不会出现错位或影响可读性。
React 表格需要速度快
优秀的 React 表格的另一个重要特性是数据操作速度,例如筛选和排序。良好的用户体验通常取决于应用程序的速度。
React Table UI 挑战
处理表格时需要考虑很多方面。让我们来逐一定义它们。
数据筛选和排序
确保这些基本功能能够快速、直观地运行非常重要——这是定义表格元素的两个主要功能。
款式
优秀的 React 表格需要精心设计样式:良好的样式可以让表格更易读、更美观。例如,当鼠标悬停在单元格上时,可以轻松选中该单元格,这将有助于用户了解自己当前所在的单元格。
响应能力
如果不改变布局以适应较小的屏幕尺寸,就很难使表格实现响应式布局。响应式表格通常外观和性能都很差。因此,在不同尺寸的屏幕上显示表格似乎是一项复杂的任务。分页等功能可以帮助您解决这个问题。
滚动
浏览器默认的滚动条对于全宽表格来说效果不错,但大多数表格的宽度都是自定义的。解决方案是开发自定义滚动条,或者使用现成的库来实现。然而,自定义滚动条在触摸屏和非触摸屏上的兼容性都非常复杂。
桌子摆放位置正确
正确地将 React 表格相对于屏幕上的其他元素定位也很重要,这样才能高效地使用它并正确读取信息。
React 表格指南
现在我们对 React 表格有了更多了解,接下来让我们看看如何开发不同类型的 React 表格。我们将以最流行的react-table库为例。create-react-app为了提高开发速度,我们显然会使用一些样板代码。
首先,你需要安装react-table库本身。为此,请运行以下命令: `npm install`react-table或 `yarn add` 。运行这些命令后,检查配置文件,你应该会看到以下条目:react-tablepackage.json
"dependencies": {
"react-table": "^7.1.0"
}
此外,如果您想修改样式,请编辑src/index.css file。
首先,我们将构建一个最简单的 React 表格,包含 3 列和 3 行。每列都有一个独立的表头。在这个例子中,我们不会构建带有分组表头的多级结构。
基本 React 表格
与其他库一样,React-table 由以下部分组成:
- 列——列的数组。列可以嵌套,嵌套的列充当标题组。此外,列可以根据需要递归嵌套;
- 数据是一个包含多行数据的数组,这些行将显示在表格中。要构建 React 表格,您需要一个数据集。在本例中,我们没有创建任何单独的 JSON 对象文件:为了提高速度,我们直接在 App.js 中创建了这些对象。
以下是一个基于 React-tables 库的简单表格的示例代码:
import React, { useState, useEffect } from 'react';
import { useTable } from 'react-table';
function Example() {
const data = React.useMemo(
() => [
{
col1: 'Minsk',
col2: '27',
col3: 'rain',
},
{
col1: 'Vilnius',
col2: '30',
col3: 'rain',
},
{
col1: 'London',
col2: '23',
col3: 'rain',
},
],
[]
)
const columns = React.useMemo(
() => [
{
Header: 'City',
accessor: 'col1', // accessor is the "key" in the data
},
{
Header: 'Temperature',
accessor: 'col2',
},
{
Header: 'Weather Forecast',
accessor: 'col3', // accessor is the "key" in the data
},
],
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({ columns, data })
return (
<div>
<table {...getTableProps()} style={{ border: 'solid 1px black }}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th
{...column.getHeaderProps()}
style={{
borderBottom: 'solid 3px red',
color: 'black',
}}
>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td
{...cell.getCellProps()}
style={{
padding: '10px',
border: 'solid 1px gray',
}}
>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
);
}
export default Example;
请注意,扩展运算符用于更轻松地展开表达式。
我们为所有列都设置了访问器,访问器指向数据对象中的数据。我们的数据位于数组中的 show 对象内——这就是为什么所有访问器都以 show 为前缀的原因。
另外,我们来解释一下上面代码中使用的函数和钩子的含义:
useTable该钩子函数接受选项和插件来构建表格实例。基本选项包括列和数据。- getTableProps 函数用于解析表格包装器所需的任何属性。内置的表格属性为 {role: “table”},可以进行自定义。
getTableBodyProps该函数用于解析表格主体包装器所需的任何属性。内置的表格属性为 {role: “rowgroup”},可以进行自定义。prepareRow这是一个必须在任何要显示的行上调用的函数。它负责准备要渲染的行。headerGroups行是由列和数据派生的内部数据结构。
React 表格排序
行排序是 React 表格的基本且必备的功能。要在 React 表格中实现列排序,您需要使用useSortBy可选的 Hook 插件。我们得到了以下结果:
更新代码src/App.js如下所示:
import React, { useState, useEffect } from 'react';
import { useTable, useSortBy } from 'react-table';
function Example() {
const data = React.useMemo(
() => [
{
col1: 'Minsk',
col2: '27',
col3: 'rain',
},
{
col1: 'Vilnius',
col2: '30',
col3: 'rain',
},
{
col1: 'London',
col2: '23',
col3: 'rain',
},
],
[]
)
const columns = React.useMemo(
() => [
{
Header: 'City',
accessor: 'col1', // accessor is the "key" in the data
},
{
Header: 'Temperature',
accessor: 'col2',
},
{
Header: 'Weather Forecast',
accessor: 'col3', // accessor is the "key" in the data
},
],
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({ columns, data }, useSortBy);
return (
<div>
<table {...getTableProps()} style={{ border: 'solid 1px black' }}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
style={{
borderBottom: 'solid 3px red',
color: 'black',
}}
>
{column.render('Header')}
<span>
{column.isSorted
? column.isSortedDesc
? '🔽'
: '🔼'
: ''}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td
{...cell.getCellProps()}
style={{
padding: '10px',
border: 'solid 1px gray',
}}
>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
);
}
export default Example;
我们useSortBy在声明useTable钩子之后使用了该插件。
getSortByToggleProps()是一个用于在切换排序方向时解析所需属性的函数。
第 29 行至第 31 行显示了排序列的降序或升序箭头。
排序过程如下:
单击列标题可在升序、降序和无排序之间切换。如果按住 Shift 键并单击列标题,则其他列的排序状态将被保留,新列随后将按此排序。这样就实现了多列排序。
筛选 React 表格
这是 React-table 的另一个默认功能。为此,我们需要在代码中添加 `filter`useFilters和 ` useGlobalFilterfilter` 这两个钩子。这两个钩子的区别在于,前者负责过滤特定列,而后者则作用于整个表格——任何列和行。
在这种情况下,代码如下所示:
import React from 'react';
import { useTable, useSortBy, useFilters, useGlobalFilter, useAsyncDebounce } from 'react-table';
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length
const [value, setValue] = React.useState(globalFilter)
const onChange = useAsyncDebounce(value => {
setGlobalFilter(value || undefined)
}, 200)
return (
<span>
Search:{' '}
<input
value={value || ""}
onChange={e => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`${count} records...`}
style={{
fontSize: '1.1rem',
border: '0',
}}
/>
</span>
)
}
// Define a default UI for filtering
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length
return (
<input
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
)
}
function Example() {
const data = React.useMemo(
() => [
{
col1: 'Minsk',
col2: '27',
col3: 'rain',
col4: '739',
col5: '90',
},
{
col1: 'Vilnius',
col2: '30',
col3: 'rain',
col4: '740',
col5: '87',
},
{
col1: 'London',
col2: '23',
col3: 'rain',
col4: '743',
col5: '77',
},
{
col1: 'Madrid',
col2: '34',
col3: 'sunny',
col4: '738',
col5: '40',
},
{
col1: 'Warsaw',
col2: '25',
col3: 'heavy rain',
col4: '739',
col5: '88',
},
],
[]
)
const columns = React.useMemo(
() => [
{
Header: 'City',
accessor: 'col1', // accessor is the "key" in the data
},
{
Header: 'Temperature',
accessor: 'col2',
},
{
Header: 'Weather Forecast',
accessor: 'col3',
},
{
Header: 'Pressure',
accessor: 'col4',
},
{
Header: 'Humidity',
accessor: 'col5',
},
],
[]
)
const defaultColumn = React.useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state,
visibleColumns,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
},
useFilters,
useGlobalFilter,
useSortBy
);
return (
<div>
<table {...getTableProps()} style={{ border: 'solid 1px black' }}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
style={{
borderBottom: 'solid 3px red',
color: 'black',
}}
>
{column.render('Header')}
<span>
{column.isSorted
? column.isSortedDesc
? '🔽'
: '🔼'
: ''}
</span>
<div>{column.canFilter ? column.render('Filter') : null}</div>
</th>
))}
</tr>
))}
<tr>
<th
colSpan={visibleColumns.length}
style={{
textAlign: 'left',
}}
>
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
</th>
</tr>
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td
{...cell.getCellProps()}
style={{
padding: '10px',
border: 'solid 1px gray',
}}
>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
);
}
export default Example;
其他 react-table 基本功能
React-table 还允许您使用现成的插件实现基本的表格功能,例如分页、通过复选框选择行、列分组、列排序,甚至列拖放。您只需在代码中添加相应的钩子即可。API 参考文档详细描述了使表格正常工作所需的所有操作。
最佳 React 表格库及示例
在本部分,我们将介绍一些优秀的 React 表格库及其示例:如今,手动构建和设置表格样式已不再高效,因为市面上已经有大量现成的表格库可供选择。我们将逐一介绍每个表格库的优缺点,并指出它们之间的区别。
React-Table
React Table 是 React 中最受欢迎的表格库之一,在 GitHub 上拥有近 15,000 个 star。react-table 库非常轻量级,提供了构建简单表格所需的所有基本功能。现在,在版本 7 发布后,它也支持 Hooks。此外,该库采用零设计理念,因此您可以完全控制表格的渲染和外观。React-table 的另一个强大之处在于其插件生态系统:如果您想扩展表格的功能,只需添加相应的 Hook 即可。
优点
- 易于定制;
- 无头模式;
- 支持透视和聚合;
- 广泛的插件生态系统;
- 轻量级(5kb – 14kb+,具体取决于使用的功能)。
缺点
- 有些情况下,相关文件资料有限;
- 我们认为,此表不适用于大型数据集。
显著特点
- 全局搜索插件;
- 基本筛选和排序选项;
- 根据数据类型(数字、字符串、布尔值、选择输入等)对列进行自定义排序和筛选;
- 支持分页;
- 能够创建自定义插件钩子。
简单回顾一下:react-table 适用于需要搜索、排序、筛选等基本功能的简单表格,例如基本的体育统计数据、天气预报、基本财务数据、用户管理表格等等。
布林图姆网格
Bryntum Grid 是一款功能强大且高性能的表格组件,能够处理超过 10 万行的数据,同时还能提供出色的用户体验。Bryntum Grid 使用纯 JavaScript 开发,因此与框架无关。不过,它也提供了 React 封装,可以无缝集成到您的项目中。这款表格的主要缺点是它并非纯 React 应用,而且是一个付费库。考虑到价格,您肯定希望获得纯 React 的表格组件。
特征
- 锁定/冻结的柱子;
- 细胞编辑;
- 自定义单元格渲染;
- 专人支持;
- 使用 SASS 可以轻松自定义分页主题。
煎锅
Griddle 是一个可定制架构的 React 数据网格组件。它自带一些基本约定和功能,但几乎可以自定义任何内容(组件、方法等)。为了鼓励自定义功能的复用,Griddle 支持插件。插件是打包的 Griddle 自定义功能,可以复用或共享。然而,该库似乎已被弃用。缺点:该库的支持似乎已停止——最后一次提交是在 2019 年 7 月。
DevExtreme React DataGrid
DevExtreme React Grid 组件用于显示来自本地或远程数据源的表格数据。它支持分页、排序、筛选、分组和其他数据生成选项,以及行选择和数据编辑功能。由于支持托管和无人值守状态模式,Grid 组件既可用于常规应用程序,也可用于基于 Redux 的应用程序。DevExtreme Grid 组件采用可组合、可扩展的插件式架构,并提供内置的 Bootstrap 和 Material-UI 渲染功能以及主题创建功能。
显著特点
- 纯 React;
- 虚拟滚动;
- 多列排序和分组;
- 树状视图模式;*自定义 UI 渲染。
Rsuite React Table
这是 React Table 的一个组件,支持虚拟化、固定列和表头、树状视图等功能。这个库的优点在于它为每个功能都提供了大量的示例。
优点
- 库提供排序、可扩展子节点和 RTL 功能;
- 包含大量示例的详细文档;
- 内部包含许多预装组件。
缺点
- 定制这个库可能有点挑战性;
- 该图书馆没有大型社区,也没有积极的发展。
React 虚拟化
React-virtualized 是一个 React 表格库,针对大型数据集进行了性能优化。严格来说,它并非一个表格库,而是一套用于高效渲染大型列表和表格数据的 React 组件。如果您需要管理大量数据,不妨考虑使用 React-virtualized。它的文档非常详尽,社区也十分活跃,在 GitHub 上拥有超过 1.8 万颗星。
对于一般使用场景,这个库功能过于强大,其 API 也过于复杂。对于自定义时间线、包含无限长日历的图表以及处理大型数据集的复杂 UI 元素,您可以考虑使用 react-virtualized。
React 数据网格
React Data Grid 是一个 React 表格库,用于创建类似于 Google 表格和 MS Excel 的应用程序。它拥有丰富的功能,包括数据绑定、编辑、类似 Excel 的筛选、自定义排序、行聚合,以及对 Excel、CSV 和 PDF 格式的支持。
优点
- 闪电般快速的渲染;
- 丰富的编辑和格式化功能;
- 可配置和可定制;
- 功能齐全,包含Excel的诸多特性,例如单元格复制和粘贴。
缺点
- 表格的开发一开始就比较复杂;
- 文件记录不完善;
- 它默认不支持分页;
- 它不容易进行自定义。
主要特点
- 类似Excel的筛选和分组选项;
- 数据导出格式不限:PDF、CSV 和 Excel;
- 直接编辑列;
- 支持对无限长表格行进行虚拟渲染;
- 使用 Bootstrap 进行样式设计。
Kendo React Grid 组件
Kendo React Grid 组件是 React 开发者可用的最强大的数据网格组件之一,包含许多必备功能。React 数据表拥有许多复杂的功能:列的重新排序和调整大小、显示层级数据、列菜单和上下文菜单。这些功能基于当前选定的行或列提供额外的功能、自定义渲染选项等等。此外,Kendo React 库开箱即用,符合许多安全性和可访问性标准。
优点
- 零依赖;
- 100 多种功能,可有效操控数据比特数;
- 文档结构非常清晰,内容全面;
- 任选3个主题;
- 提供专属支持团队选项。
缺点
- 价格有点高;
- 我们认为自定义样式的实现可能会有点棘手。
如果您希望表格/网格成为您应用程序中功能非常全面、文档齐全且有专门支持的组件,我们建议您了解一下 Kendo UI React 网格。
React 数据表
React-datasheet 与 react-data-grid 类似。它在 GitHub 上有很多项目,维护良好,并且拥有一个非常活跃且乐于助人的社区。正如您可能已经注意到的,该库的主要目标是帮助您在 React 上创建类似 Google Sheets/Excel 的应用程序。该项目预置了样式和函数,因此您可以开箱即用,获得所需的视图和复杂功能。但是,请注意,该库不适用于功能有限的小型基础表格。
优点
- 有据可查;
- 界面美观;
- 良好的定制化服务;
- 预置公式表。
缺点
- 仅限于特定使用场景;
- 不适用于大型数据集。
材料表
Material Table 是目前最流行的 React 表格库之一,这得益于其Material Design 设计理念和 Material-UI 组件的使用。该项目非常易于使用和安装,即使是初学者也能轻松上手;完善的文档将大大加快开发速度。
优点
- 功能丰富;
- 预构建导出为 CSV;
- 完善的文档。
缺点
- 组件覆盖;
- 并非所有人都喜欢 Material UI。
材料表的工作原理
要开始开发,您需要通过在控制台中输入命令来安装此库。您还需要添加 Material-UI 图标yarn add。npm install
该库的工作方式如下:您只需向<MaterialTable />组件传递两个属性。`data` 属性用于以行格式显示数据。另一个 `column` 属性定义了列数。
<MaterialTable />组件的第三个属性‘title’可以用来给整个表格添加标题。请参见以下示例:
return (
<div>
<MaterialTable columns={columns} data={data} title='Flatlogic' />
</div>
);
默认情况下,material-table 库会显示搜索栏和分页功能。如果您喜欢 Material-UI 和 Material Design,Flatlogic 推荐您使用 Material-table。
RC表
rc-Table 是另一个实用的小型 React 表格库,它提供了一系列基础函数,可以帮助你构建结构良好的 React 表格。如果你想使用自定义样式,这个表格库非常适合你。此外,它还非常容易理解和上手。
优点
- 非常轻便;
- 文档中包含许多示例及源代码;
- 快速启动实际开发;
- 社区规模有限。
缺点
- 文档不太完善。有些功能根本没有描述。
因此,该库适用于小型应用程序或表格不是应用程序核心部分的应用程序。
结论
正如我们在指南中看到的,与其他库(例如 Bootstrap)相比,构建 React 表格需要花费一些精力。我们也了解到,在大多数情况下,您无需从头开始开发自己的 React 表格:已经有许多针对不同项目需求的 React 表格解决方案,包括付费和免费的。
在选择满足您需求的库时,请注意 GitHub 上的星标数量、社区活跃程度、库的更新频率以及下载频率。
但是,让我们来看看在哪些情况下你仍然可以考虑构建自己的 React 表格:
- 当您需要为表格定制用户界面时,自己构建可能更快;
- 当你的餐桌只是一个展示柜时;
- 你需要一个非常轻量级、没有任何依赖项的表格。
我们希望我们的指南和选择对您有所帮助,并且您已经选择了在构建 React 表格时要使用的库。
如果您发现我们的文章缺少一个优秀的 React 表格库,我们将很乐意考虑将其添加到合集中——请给我们留言。
关于 Flatlogic
Flatlogic致力于帮助企业加速网站开发,我们采用React、Vue、Angular、React Native和Bootstrap等技术,打造精美的Web和移动应用模板。过去几年,我们已成功为众多客户交付了100多个定制仪表盘和数据管理解决方案,客户涵盖创新型初创公司到成熟知名企业。
您可能还会喜欢以下文章:
扩展 Bootstrap 的 24 个必备免费插件、
37 个简单实用的 Web 开发人员表格模板和示例、
13 个以上的登录页面设计示例