从0到1:Umi中打造高性能React Table数据管理系统

从0到1:Umi中打造高性能React Table数据管理系统

【免费下载链接】umi A framework in react community ✨ 【免费下载链接】umi 项目地址: https://gitcode.com/gh_mirrors/umi8/umi

你是否还在为React项目中的表格功能开发头疼?筛选、排序、分页实现繁琐,大数据加载卡顿,自定义列宽时样式错乱?本文将带你基于Umi框架,使用React Table构建企业级数据表格解决方案,解决90%的表格开发痛点。

读完本文你将掌握:

  • 在Umi项目中快速集成React Table的完整流程
  • 实现排序、筛选、分页等核心功能的最佳实践
  • 处理10万+数据的虚拟滚动优化方案
  • 自定义单元格渲染与编辑功能的实现方法
  • 与Umi生态(如Dva状态管理)的无缝衔接

环境准备与项目结构

基础项目搭建

确保已安装Node.js环境(建议v14+),通过以下命令创建Umi项目:

mkdir umi-react-table-demo && cd umi-react-table-demo
npm create umi@latest

选择"App"模板,安装依赖后启动开发服务器:

npm install
npm run dev

Umi项目目录规范

Umi采用约定式路由,表格页面推荐放在src/pages目录下。典型项目结构如下:

.
├── src/
│   ├── pages/                # 页面目录
│   │   ├── table/            # 表格功能页面
│   │   │   ├── index.js      # 表格页面入口
│   │   │   └── components/   # 表格相关组件
│   ├── models/               # Dva状态管理 models/
│   ├── services/             # API请求服务 services/
│   └── utils/                # 工具函数 utils/
├── .umirc.js                 # Umi配置文件 [.umirc.js](https://link.gitcode.com/i/b1297396bd868635f82c36bee919530e)
└── package.json              # 项目依赖 [package.json](https://link.gitcode.com/i/b2d70754e7b935a154ff236faf06446d)

详细目录规范可参考官方文档:docs/guide/app-structure.md

React Table集成与基础配置

安装依赖

在项目根目录执行以下命令安装React Table核心包:

npm install react-table@7.7.0

注意:v7版本是目前稳定性和社区支持最好的版本,v8版本API变化较大,暂不推荐在生产环境使用

基础表格组件实现

src/pages/table/index.js中创建基础表格组件:

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

// 表格数据
const data = [
  { id: 1, name: '张三', age: 28, department: '研发部', salary: 25000 },
  { id: 2, name: '李四', age: 32, department: '产品部', salary: 28000 },
  { id: 3, name: '王五', age: 26, department: '测试部', salary: 22000 },
];

// 表格列定义
const columns = [
  { Header: 'ID', accessor: 'id' },
  { Header: '姓名', accessor: 'name' },
  { Header: '年龄', accessor: 'age' },
  { Header: '部门', accessor: 'department' },
  { Header: '薪资', accessor: 'salary', 
    Cell: ({ value }) => `¥${value.toLocaleString()}` 
  },
];

export default function DataTable() {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable({ columns, data });

  return (
    <div className="table-container">
      <table {...getTableProps()} style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                <th {...column.getHeaderProps()} style={{ 
                  border: '1px solid #ddd', 
                  padding: '8px', 
                  backgroundColor: '#f8f9fa' 
                }}>
                  {column.render('Header')}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map(row => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => (
                  <td {...cell.getCellProps()} style={{ 
                    border: '1px solid #ddd', 
                    padding: '8px' 
                  }}>
                    {cell.render('Cell')}
                  </td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

核心功能实现

排序与筛选

React Table内置排序功能,只需在列定义中添加sortType属性:

const columns = [
  // ...其他列
  { 
    Header: '薪资', 
    accessor: 'salary',
    sortType: 'basic' // 基础排序
  },
  { 
    Header: '部门', 
    accessor: 'department',
    // 自定义筛选器
    Filter: ({ column: { filterValue, setFilter } }) => (
      <input
        value={filterValue || ''}
        onChange={e => setFilter(e.target.value)}
        placeholder="搜索部门..."
        style={{ width: '100%', padding: '4px' }}
      />
    ),
    filter: 'includes' // 包含匹配
  }
];

useTable调用时启用筛选功能:

const {
  // ...其他属性
  state: { filters },
} = useTable({ 
  columns, 
  data,
  initialState: { 
    sortBy: [{ id: 'salary', desc: true }], // 默认按薪资降序
    pageSize: 10 
  }
});

分页控制

添加分页功能需要使用usePagination扩展钩子:

import { useTable, usePagination } from 'react-table';

// ...

const {
  // ...其他属性
  page, // 当前页数据
  canPreviousPage,
  canNextPage,
  pageOptions,
  pageCount,
  gotoPage,
  nextPage,
  previousPage,
  setPageSize,
  state: { pageIndex, pageSize },
} = useTable(
  {
    columns,
    data,
    initialState: { pageIndex: 0, pageSize: 10 },
  },
  usePagination // 应用分页扩展
);

实现分页控件:

<div className="pagination" style={{ marginTop: '16px' }}>
  <button 
    onClick={() => gotoPage(0)} 
    disabled={!canPreviousPage}
  >
    首页
  </button>
  <button 
    onClick={() => previousPage()} 
    disabled={!canPreviousPage}
  >
    上一页
  </button>
  <button 
    onClick={() => nextPage()} 
    disabled={!canNextPage}
  >
    下一页
  </button>
  <button 
    onClick={() => gotoPage(pageCount - 1)} 
    disabled={!canNextPage}
  >
    末页
  </button>
  <span>
    第 {pageIndex + 1} 页 / 共 {pageCount} 页
  </span>
  <select
    value={pageSize}
    onChange={e => setPageSize(Number(e.target.value))}
  >
    {[5, 10, 20, 50].map(size => (
      <option key={size} value={size}>
        每页 {size} 条
      </option>
    ))}
  </select>
</div>

高级特性与性能优化

虚拟滚动处理大数据

当表格数据超过1万行时,建议使用虚拟滚动。安装react-window

npm install react-window

创建虚拟滚动表格容器:

import { FixedSizeList as List } from 'react-window';

// ...

const RenderRow = ({ index, style }) => {
  const row = page[index];
  prepareRow(row);
  return (
    <tr {...row.getRowProps({ style })}>
      {row.cells.map(cell => (
        <td {...cell.getCellProps()}>
          {cell.render('Cell')}
        </td>
      ))}
    </tr>
  );
};

// 在表格body中使用虚拟列表
<tbody {...getTableBodyProps()}>
  <List
    height={400}
    itemCount={page.length}
    itemSize={50}
    width="100%"
  >
    {RenderRow}
  </List>
</tbody>

与Umi生态集成

Dva状态管理

创建表格数据模型src/models/table.js

export default {
  namespace: 'table',
  state: {
    data: [],
    loading: false,
    total: 0,
  },
  effects: {
    *fetch({ payload }, { call, put }) {
      yield put({ type: 'setLoading', payload: true });
      const response = yield call(queryTableData, payload);
      yield put({ 
        type: 'saveData', 
        payload: {
          data: response.list,
          total: response.total
        } 
      });
      yield put({ type: 'setLoading', payload: false });
    },
  },
  reducers: {
    setLoading(state, { payload }) {
      return { ...state, loading: payload };
    },
    saveData(state, { payload }) {
      return { ...state, ...payload };
    },
  },
};

在页面中连接Dva:

import { connect } from 'dva';

// ...

const mapStateToProps = ({ table, loading }) => ({
  tableData: table.data,
  total: table.total,
  loading: loading.effects['table/fetch'],
});

const mapDispatchToProps = {
  fetchTableData: (params) => ({ type: 'table/fetch', payload: params }),
};

export default connect(mapStateToProps, mapDispatchToProps)(DataTable);

样式定制与主题适配

集成Ant Design样式

如果项目使用Ant Design,可通过以下方式统一表格样式:

import 'antd/dist/antd.css'; // 或 'antd/dist/antd.less'
import { Table as AntTable } from 'antd';

// 使用Ant Design的表格样式类
<div className="ant-table ant-table-default ant-table-scroll-position-left">
  {/* React Table内容 */}
</div>

完整代码与项目实战

完整示例代码可参考Umi官方示例库:docs/guide/examples-and-boilerplates.md

建议项目结构:

src/
├── pages/
│   ├── table/
│   │   ├── index.js          # 表格页面入口
│   │   ├── components/       # 表格组件
│   │   │   ├── TableHeader.js # 自定义表头
│   │   │   ├── TableCell.js   # 自定义单元格
│   │   │   └── Pagination.js  # 分页组件
│   │   └── hooks/            # 自定义钩子
│   │       ├── useTableData.js # 表格数据处理
│   │       └── useTableColumns.js # 列配置

总结与最佳实践

React Table在Umi项目中的应用要点:

  1. 基础配置:核心依赖react-table,基础功能零配置即可使用
  2. 性能优化:1万行以内用普通渲染,超过1万行必须使用虚拟滚动
  3. 状态管理:复杂表格建议使用Dva管理状态,简化数据流转
  4. 样式方案:小型项目可用内联样式,大型项目建议集成UI库样式
  5. 扩展性:通过自定义hooks封装表格逻辑,提高代码复用率

通过本文介绍的方法,你可以快速构建出功能完善、性能优异的企业级数据表格。更多高级用法可参考React Table官方文档和Umi框架指南:docs/guide/

点赞+收藏本文,关注作者获取更多Umi开发实战技巧!下一篇:《Umi中实现React Table的导出与打印功能》

【免费下载链接】umi A framework in react community ✨ 【免费下载链接】umi 项目地址: https://gitcode.com/gh_mirrors/umi8/umi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值