如何在React中用表格进行数据可视化

629 阅读8分钟

用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-componentsreact-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;

我们把columnsdata 作为道具传给了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;

你注意到我们是如何将columnsdata 道具传递给Table 组件,以及如何将它们的值分配给useMemo() 钩子。

useMemo() 可以确保数据在每次渲染时不会被重新创建。

如果我们不这样设置,react-table 会认为它正在接收新的数据,这将导致重新编译代码,而这又会导致性能不佳。

下面是项目的结果。

a demo of the react-table project

我希望这篇文章能很好地指导你如何在React中实现表格的可视化数据。

总结

这篇文章提供了一个在React中处理数据表的开端。

我们使用React开发了一个应用程序,并实现了react-table 库来演示这一概念。

在这个项目上的工作应该是对在react中构建响应式数据表格的一个深入了解。