用React中的表格进行数据可视化
在React中使用表格一直是一个负担,因为开发者会遇到与表格的样式、响应性和数据的正确渲染有关的问题。
本文将介绍一种方法,使我们能够通过一个名为react-table 的npm包正确地将表格中的数据可视化。
React table是一个专注于React Hooks模式的库,因此抽象出了创建或硬编码HTML表格元素的需要。
前提条件
要跟上这篇文章,你应该知道以下内容。
- React:一个用于创建单页应用程序的JavaScript框架
- JavaScript的扩散运算符。
- React中的PropTypes验证。
- React中的道具处理。
- React Hooks。
- React的风格化组件。
起步
本文的范围是围绕被称为Nextjs 的react框架。我们也可以使用create-react-app 来构建这个项目。
npx create-next-app [your-app-name]
next.js应用程序的文件结构与create-react-app"的文件架构完全不同。
在这个项目中,我们将只与我们需要的文件进行交互,以避免被淹没。
|--pages
| |-- _app.js
| |-- index.js
|--src
| |-- components
| | |-- Table.js
| |-- data.json
| |-- columns.js
|__
现在我们已经熟悉了上面的文件结构。让我们继续安装styled-components 和react-table 包。
npm install styled-components react-table
组件和文件的概述
_app.js:是应用程序的根文件。它看起来类似于create-react-app 中的index.js 文件。
在这个文件中,你可以。
- 应用任何全局样式
- 添加新的主题
- 为整个应用程序提供上下文
- 导入
redux提供者上下文,以管理你的应用程序的状态(如果你使用redux)。
import Head from "next/head";
import React from "react";
function MyApp({ Component, pageProps }) {
return (
<React.Fragment>
<Head>
<meta name="theme-color" content="#3c1756" />
<title>A React Table</title>
</Head>
<Component {...pageProps} />
</React.Fragment>
);
}
export default MyApp;
在第一个_app.js 代码段中,Head 组件从"next/head" 中被导入。这个组件执行的功能与正常的HTML<head> 元素相同。
在Head 组件中,我们可以添加不同的子元素,如描述当前路由或页面的<title> 元素,导入样式表或设置页面的favicon的<link> 元素,用于SEO优化的<meta> 标签。
index.js: 是我们的默认路线。
当运行开发服务器时,我们在文件中做的任何事情都会显示在这个地址:https://localhost:3000/ 。
npm run dev
Table.js:是持有从data.json和 的数据的用户界面的组件。columns.js.data.json:持有将在Table组件中呈现的用户对象的数组。我们将使用从Jsonplaceholder用户API复制的数据,而不是自己编写API调用。
[
{
"id": 1,
"name": "Leanne Graham",
"email": "Sincere@april.biz",
"username": "Bret",
"phone": "1-770-736-8031 x56442",
"company_name": "Romaguera-Crona",
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna@melissa.tv",
"phone": "010-692-6593 x09125",
"company_name": "Romaguera-Crona",
},
// the remaining user objects fall below
];
我们正在减少数组中的用户对象的数量,以便这篇文章可以更短。
API端点为每个API调用提供了一个数组中的十个用户对象的列表。
columns.js: 也是一个对象数组,存储了我们想在表头呈现的项目。
export const COLUMNS = [
{
Header: "S/N",
accessor: "id",
},
{
Header: "Fullname",
accessor: "name",
},
{
Header: "Email address",
accessor: "email",
},
{
Header: "Username",
accessor: "username",
},
{
Header: "Phone number",
accessor: "phone",
},
{
Header: "Company",
accessor: "company_name",
},
];
注意我们是如何在对象中声明accessor 这个键的。accessor 更像是属性的定位器,它在src/data.json 。
让我们比较一下下面这两个对象。
// columns.js
{
Header: "Company",
accessor: "company_name",
},
// data.json
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna@melissa.tv"
"phone": "010-692-6593 x09125",
"company_name": "Romaguera-Crona"
},
accessor 属性在column.js 中的值是company_name ,它又从json文件中渲染了相应的属性值。
将组件放在一起
在上一节中,我们安装了next.js应用程序中所需要的必要依赖项。
此外,我们还看到了保存表的数据的文件内容以及它们的功能。
本节将开始查看下面component 文件夹中的Table.js 的内容。
import React from "react";
import styled from "styled-components";
// the styled component that serves as a
// wrapper for the table component goes here
const TableContainer = styled.div`
table {
width: 100%;
height: 100%;
border-collapse: collapse;
box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.08);
}
thead {
height: 64px;
background: #3c1742;
}
thead th {
font-size: 14px;
color: ;
text-align: left;
padding: 0 30px;
}
tr {
height: 64px;
border-bottom: 2px solid grey;
}
tr td {
padding: 0 30px;
border-bottom: 1px solid #3c1742;
}
@media only screen and (max-width: 992px) {
table {
white-space: nowrap;
}
}
`
const Table = ({ columns, data }) => {
// react-table hooks will go here
return (
// Table's JSX will go here
);
}
export default Table;
上面的表格组件主要是指表格的样式。
让我们来看看下面的一些属性。
table 选择器将表格的宽度和高度设置为:100% ,使其能够响应地接收更多的列和行。
table {
width: 100%;
margin-top: 20px;
height: 100%;
}
媒体查询规则将表格的text-wrap 属性设置为no-wrap ,最大屏幕宽度为992px 。
@media only screen and (max-width: 992px) {
table {
white-space: nowrap;
}
}
在表格组件上工作
import React from "react";
import { useTable } from "react-table";
import styled from "styled-component";
const TableContainer = styled.div`
...
`;
const Table = ({ columns, data }) => {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({ columns, data });
return (
<TableContainer>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup, index) => (
<tr {...headerGroup.getHeaderGroupProps()} key={index}>
{headerGroup.headers.map((column, index) => (
<th key={index} {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, index) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()} key={index}>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</TableContainer>
);
};
export default Table;
让我们把上面的组件分成小块。
- 下面的片段说明了使用
react-table库中的useTable()钩子创建表格实例的过程。
import { useTable } from "react-table";
const Table = ({ columns, data }) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({ columns, data, });
return (
...
);
}
export default Table;
我们把columns 和data 作为道具传给了useTable() 钩子,因为它必须正常工作。
useable()函数的析构赋值使我们能够访问表的实例方法。
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({ columns, data });
这些道具也需要被记忆化。这个过程可以通过使用useMemo() 钩子来完成。我们将在下一节中讨论其中的原因。
getTableProps()是我们用useTable()钩子创建的表实例的方法之一。注意我们是如何把它作为一个属性传递给<table>元素的。这个语法(…),被称为spread operator。
const Table = ({ columns, data }) => {
const { ... } = useTable({ columns, data, });
return (
<TableContainer>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup, index) => (
<tr {...headerGroup.getHeaderGroupProps()} key={index}>
{headerGroup.headers.map((column, index) => (
<th key={index} {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
...
</table>
</TableContainer>
);
};
export default Table;
当我们把…getTableProps() 作为一个属性应用到table 元素时,我们正在使这个方法(getTableProps() 方法)的其他属性被我们访问。
这就是为什么我们可以做这样的事情。
<thead>
{headerGroups.map((headerGroup, index) => (
<tr {...headerGroup.getHeaderGroupProps()} key={index}>
{headerGroup.headers.map((column, index) => (
<th key={index} {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
让我们看一下下面这个例子,它说明了一个传播操作的过程。
// a daughter array with an object in it
// showing the properties of this person
let daughter = [
{
firstname: "Bola",
lastname: "Jones",
hair_color: "black",
role: "daughter",
},
];
// a family array showing the list of members
// in a family and their properties.
let family = [
{
firstname: "Dapo",
lastname: "Jones",
hair_color: "black",
role: "Father",
},
{
firstname: "Teni",
lastname: "Jones",
hair_color: "red",
role: "Mother",
},
...daughter,
];
console.log(family);
通过传播操作,daughter 数组被添加到family 数组中。可以通过map() 函数在数组中循环,或者使用数组语法来访问它。
console.log(family[2].role); // prints daughter to the console
索引页组件
在前面的章节中,我们看了每个组件的内容,它们都执行的功能,useTable() 钩子和传播操作符的功能,以及表实例方法在幕后如何工作。
在本节中,我们将介绍这一过程的最后步骤。
首先,我们将把Table 组件导入到pages/index.js ,并添加一个在桌面模式下可见的自定义滚动条。
让我们开始吧。
我们正在从各自的文件中导入COLUMNS 模块和tableData 。
import React from "react";
import styled from "styled-components";
import Table from "../../components/Table";
import { COLUMNS } from "../../src/Columns";
import tableData from "../../src/table_data.json";
现在,让我们看看包裹着索引页的样式组件;我们也会去看看一些基本样式块的功能。
import styled from "styled-components";
const TableWrapper = styled.section`
padding: 0 150px 0 150px;
padding-bottom: 130px;
h1 {
text-align: center;
color: #000;
font-size: 36px;
font-weight: 900;
padding: 50px 0 0 0;
}
.table-container {
height: 700px;
overflow: auto;
}
.table-container::-webkit-scrollbar {
width: 10px;
}
.table-container::-webkit-scrollbar-thumb {
height: 4px;
background: #3c1742;
border-radius: 10px;
}
.table-container::-webkit-scrollbar-track {
border: 1px solid #3c1742;
border-radius: 10px;
}
@media only screen and (max-width: 992px) {
padding: 0 15px 0 15px;
padding-bottom: 130px;
.table-container::-webkit-scrollbar {
display: none;
}
}
下面的代码段表示自定义滚动条样式。
.table-container::-webkit-scrollbar {
width: 10px;
}
.table-container::-webkit-scrollbar-thumb {
height: 4px;
background: #3c1742;
border-radius: 10px;
}
.table-container::-webkit-scrollbar-track {
border: 1px solid #3c1742;
border-radius: 10px;
}
下面的代码段使表格在移动和桌面屏幕上都能响应。然而,在移动屏幕上,自定义滚动条是隐藏的。
.table-container {
height: 700px;
overflow: auto;
}
@media only screen and (max-width: 992px) {
.table-container::-webkit-scrollbar {
display: none;
}
}
现在我们了解了这些样式,让我们来看看在用户界面上渲染完整数据的主要组件。
import React from "react";
import { COLUMNS } from "../../src/Columns";
import tableData from "../../src/table_data.json";
import styled from "styled-components";
const TableWrapper = styled.section``;
const UserTable = () => {
return (
<TableWrapper>
<h1>Leaderboard</h1>
<div className="table-container">
<Table
columns={React.useMemo(() => COLUMNS)}
data={React.useMemo(() => tableData)}
/>
</div>
</TableWrapper>
);
};
export default UserTable;
你注意到我们是如何将columns 和data 道具传递给Table 组件,以及如何将它们的值分配给useMemo() 钩子。
useMemo() 可以确保数据在每次渲染时不会被重新创建。
如果我们不这样设置,react-table 会认为它正在接收新的数据,这将导致重新编译代码,而这又会导致性能不佳。
下面是项目的结果。

我希望这篇文章能很好地指导你如何在React中实现表格的可视化数据。
总结
这篇文章提供了一个在React中处理数据表的开端。
我们使用React开发了一个应用程序,并实现了react-table 库来演示这一概念。
在这个项目上的工作应该是对在react中构建响应式数据表格的一个深入了解。