R

React-Table 如何使用 React Table 和 TailwindCSS 构建可操作的数据表

2025-06-05

React-Table如何使用 React Table 和 TailwindCSS 构建可操作的数据表

在本文中,我们将了解如何使用 React Table 和 TailwindCSS 构建可操作的数据表。数据表是应用程序仪表板的重要 UI 元素。
在前端开发中,了解如何构建可靠的数据表始终至关重要。

什么是数据表?

在深入探讨技术部分之前,让我们先尝试了解什么是数据表以及为什么它从用户的角度来看如此重要。

数据表是数据列表的清晰表示。它是一种以行和列表示数据的方式。

为什么它很重要?

假设您正在经营一家提供在线服务的电子商务商店。您希望以美观的格式查看每月的订单,并且还想了解特定月份中最常购买的商品。

传统方法之一是在 Excel 或 Google Sheet 中管理所有这些数据。您仍然可以这样做。但是,一旦数据变得庞大,就会变得麻烦。

这就是数据表的作用。基本上,您可以使用表中的所有功能(例如排序顺序、过滤选项和分页数据)来管理表中的所有报告数据。

它将利用所有功能帮助您轻松地管理数据。

演示

在这里,我们将构建一个智能数据表,我们可以在表中动态添加行并在数据表本身中添加/编辑数据。

设置和安装

在这里,我们需要一个具有数据表的客户端应用程序。然后它将数据发送到服务器,服务器将数据保存到 google sheet。

但是,本文主要关注使用 React Table 构建数据表。如果您想了解如何在 Node.js 中集成 Google Sheet,请查看本文

让我们使用以下命令创建一个 React 应用程序,create-react-app

npx create-react-app client
Enter fullscreen mode Exit fullscreen mode

现在,您的根目录中将有一个 React 应用程序。

反应表文件夹结构

之后,安装react-table用于在 React 应用程序中创建表格的无头 UI。

npm i react-table
Enter fullscreen mode Exit fullscreen mode

最后,让我们在你的 React 应用程序中安装 TailwindCSS。我不想深入讲解这个,因为已经有关于此设置的详细教程了。可以看看这篇文章。

入门

首先,表格主要包含行和列。反应表也是如此。因此,您需要在反应表钩子中传递数据和列来呈现列和行。

让我们创建一个反应表组件,它以列和行作为参数来呈现表格。

import React from "react";
import { useTable } from "react-table";

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

  });

  return (
    //Render UI Here
  );
};

export default Table;
Enter fullscreen mode Exit fullscreen mode

在这里,我们将列和数据作为道具,并将其传递给名为 useTable 的钩子,该钩子返回一些道具以在我们的组件中呈现表格组件。

让我们逐一分解,以便更好地理解,

对于任何表,我们都会有 HTML 语义例如table,,,。我们需要这些语义的一些属性才能使其正常工作。例如,从头开始创建分页或过滤逻辑。您可能需要访问 HTML 元素。thtbodytrtd

react-table提供开箱即用的功能。为此,您需要将 useTable 钩子的 props 映射到您的 HTML 元素。

这就是 hooks 中的 props 的用途。您useTable还可以使用自定义属性覆盖这些属性。一些 props 包括getTablePropsgetTableBodyProps等等。

<table className="min-w-full divide-y divide-gray-200"
{...getTableProps()} />

</table>
Enter fullscreen mode Exit fullscreen mode

这里,我们有一张包含getTableProps来自反应表的 props 的表,并与之映射。

像这样,我们需要渲染theadtbody等等

<thead>
  {headerGroups.map(headerGroup => (
    <tr {...headerGroup.getHeaderGroupProps()}>
      {headerGroup.headers.map(column => (
        <th
          className="px-6 py-3 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"
          {...column.getHeaderProps()}
        >
          {column.render("Header")}
        </th>
      ))}
    </tr>
  ))}
</thead>
Enter fullscreen mode Exit fullscreen mode

这里要注意的重要一点是,headerGroup返回标题,它将成为表格的标题。

反应表标题组

之后,我们tbody用同样的图案进行渲染,

<tbody className="bg-white divide-y divide-gray-200" {...getTableBodyProps()}>
  {rows.map((row, i) => {
    prepareRow(row)
    return (
      <tr {...row.getRowProps()}>
        {row.cells.map(cell => {
          return (
            <td
              className="px-6 py-4 whitespace-no-wrap text-sm leading-5 font-medium text-gray-900"
              {...cell.getCellProps()}
            >
              {cell.render("Cell")}
            </td>
          )
        })}
      </tr>
    )
  })}
</tbody>
Enter fullscreen mode Exit fullscreen mode

请参阅此处的完整Table/index.js组件,

import React from "react"
import { useTable } from "react-table"

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

  return (
    <div className="flex flex-col w-full">
      <div className="-my-2 py-2 sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
        <div className="align-middle inline-block min-w-full shadow sm:rounded-lg border-b border-gray-200">
          <table
            className="min-w-full divide-y divide-gray-200"
            {...getTableProps()}
          >
            <thead>
              {headerGroups.map(headerGroup => (
                <tr {...headerGroup.getHeaderGroupProps()}>
                  {headerGroup.headers.map(column => (
                    <th
                      className="px-6 py-3 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"
                      {...column.getHeaderProps()}
                    >
                      {column.render("Header")}
                    </th>
                  ))}
                </tr>
              ))}
            </thead>
            <tbody
              className="bg-white divide-y divide-gray-200"
              {...getTableBodyProps()}
            >
              {rows.map((row, i) => {
                prepareRow(row)
                return (
                  <tr {...row.getRowProps()}>
                    {row.cells.map(cell => {
                      return (
                        <td
                          className="px-6 py-4 whitespace-no-wrap text-sm leading-5 font-medium text-gray-900"
                          {...cell.getCellProps()}
                        >
                          {cell.render("Cell")}
                        </td>
                      )
                    })}
                  </tr>
                )
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  )
}

export default Table
Enter fullscreen mode Exit fullscreen mode

让我们Table在父组件内导入组件并将所需的数据作为 props 传递。

在中添加以下代码App.js

import React, { useState, useEffect } from "react"
import Table from "./components/Table"

function App() {
  const [rowdata, setRowData] = useState([])

  const onAddRowClick = () => {
    setRowData(
      rowdata.concat({ username: "", email: "", gender: "", phone: "" })
    )
  }

  const columns = [
    {
      Header: "Name",
      accessor: "username",
    },
    {
      Header: "Email",
      accessor: "email",
    },
    {
      Header: "Gender",
      accessor: "gender",
    },
    {
      Header: "Phone",
      accessor: "phone",
    },
  ]

  return (
    <div className="container mx-auto">
      <button
        onClick={onAddRowClick}
        className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
      >
        Add Row
      </button>
      <div className="flex justify-center mt-8">
        <Table columns={columns} data={rowdata} />
      </div>
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

这里,我们将列和行传入Table组件。需要注意的是columns数组的结构。它包含Headeraccessor

Headerth如果你还记得的话,这就是我们在表格中呈现的内容,

{
  column.render("Header")
}
Enter fullscreen mode Exit fullscreen mode

accessor指的是 Table 组件中要呈现的行名称。

到目前为止,我们已经了解了如何在表格中呈现列和行。让我们看看如何在行内呈现可编辑单元格。

渲染可编辑单元格

要呈现可编辑的单元格,您需要在列数组内呈现自定义单元格组件。

创建一个组件EditableCell/index.js并添加以下代码,

import React from "react"

const EditableCell = ({
  value: initialValue,
  row: { index },
  column: { id },
  updateMyData, // This is a custom function that we supplied to our table instance
}) => {
  // We need to keep and update the state of the cell normally
  const [value, setValue] = React.useState(initialValue)

  const onChange = e => {
    setValue(e.target.value)
  }

  // We'll only update the external data when the input is blurred
  const onBlur = () => {
    updateMyData(index, id, value)
  }

  // If the initialValue is changed external, sync it up with our state
  React.useEffect(() => {
    setValue(initialValue)
  }, [initialValue])

  return <input value={value} onChange={onChange} onBlur={onBlur} />
}

export default EditableCell
Enter fullscreen mode Exit fullscreen mode

在这里,我们将一些值和函数作为 props 传递。让我们逐一分解,

  • 值 - 它将值返回到自定义单元格,您将需要初始值来在组件内呈现它
  • row - 它返回插入单元格的行的值。
  • 列 - 它返回您要添加单元格的列的值。
  • updateMyDate - 它是在 onBlur 事件上更新父组件的道具

您需要将自定义组件映射到列数组中

const columns = [
  {
    Header: "Name",
    accessor: "username",
    Cell: EditableCell,
  },
  {
    Header: "Email",
    accessor: "email",
    Cell: EditableCell,
  },
  {
    Header: "Gender",
    accessor: "gender",
    Cell: ({
      value: initialValue,
      row: { index },
      column: { id },
      updateMyData,
    }) => {
      const onItemClick = value => {
        console.log("value", value)
        updateMyData(index, id, value)
      }

      return (
        <DropDown
          options={[
            { label: "Male", value: "male" },
            { label: "Female", value: "female" },
          ]}
          title={"Select Gender"}
          selectedValue={initialValue}
          onItemClick={onItemClick}
        />
      )
    },
  },
  {
    Header: "Phone",
    accessor: "phone",
    Cell: EditableCell,
  },
]
Enter fullscreen mode Exit fullscreen mode

如果你仔细观察,我们会在实现自定义输入的相同内容中插入一个下拉菜单。

搜索和过滤

最后,您需要实现数据表的搜索和过滤功能。这将很简单,因为我们在表组件之外呈现搜索和过滤。

我们不需要在内部实现它Table。我们可以直接操作我们的父组件状态并根据搜索或过滤输入来过滤数据。

const [rowdata, setRowData] = useState([])
const [filteredData, setFilteredData] = useState([])

// Searchbar functionality
const onSearchbarChange = e => {
  const value = e.target.value

  if (value === "") {
    setFilteredData(rowdata)
  } else {
    if (filteredData.length > 0) {
      const result = filteredData.filter(item => item.email === value)

      setFilteredData(result)
    } else {
      const result = rowdata.filter(item => item.email === value)

      setFilteredData(result)
    }
  }
}

// Filter functionality
const onItemClick = e => {
  console.log("e", e)
  if (e === "all") {
    setFilteredData(rowdata)
  } else {
    const result = rowdata.filter(item => item.gender === e)

    setFilteredData(result)
  }
}
Enter fullscreen mode Exit fullscreen mode

结论

在您的 Web 开发生涯中,了解如何构建数据表非常重要。因为您可能需要在开发生涯中的某个时间点实现它。不断探索它的概念并进行大量练习以使自己变得更好。

源代码

文章来源:https://dev.to/ganeshmani/how-to-build-an-actionable-data-table-with-react-table-and-tailwindcss-3891
PREV
在 Node.js 中实现作业调度程序
NEXT
JavaScript 是如何工作的?🤔