导读:本期聚焦于小伙伴创作的《Ant Design 3.x Table大数据渲染性能优化方案:虚拟滚动、分页加载与无限滚动实战》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Ant Design 3.x Table大数据渲染性能优化方案:虚拟滚动、分页加载与无限滚动实战》有用,将其分享出去将是对创作者最好的鼓励。

Ant Design 3.x Table 大数据量渲染慢,如何优化?

在使用 Ant Design 3.x 的 Table 组件时,当数据量达到数千甚至上万条时,页面渲染会变得非常缓慢,甚至出现卡顿现象。这主要是因为 Table 组件默认会一次性渲染所有数据,导致浏览器 DOM 节点过多,性能急剧下降。本文将介绍几种有效的优化方案。

问题分析

Ant Design 3.x Table 组件在数据量较大时性能瓶颈主要体现在:

  • 一次性渲染大量 DOM 节点,占用大量内存

  • 表格列过多时,每行的单元格数量多,渲染成本高

  • 排序、筛选等操作触发全量数据重新渲染

优化方案

方案一:虚拟滚动(推荐)

虚拟滚动是解决大数据量表格渲染性能问题的最佳方案。它只渲染可视区域内的行,大幅减少 DOM 节点数量。

可以使用第三方库 react-virtualizedreact-window 来实现虚拟滚动表格。

实现步骤:

  1. 安装依赖:npm install react-virtualized --save

  2. 自定义表格组件,结合 react-virtualized 的 List 组件实现虚拟滚动

代码示例:

import React from 'react';
import { Table } from 'antd';
import { List } from 'react-virtualized';
import 'react-virtualized/styles.css'; // 引入样式

class VirtualTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      dataSource: [], // 原始数据
      columns: props.columns,
      height: props.height || 400,
      rowHeight: props.rowHeight || 50,
    };
  }

  componentDidMount() {
    // 模拟加载大量数据
    const data = [];
    for (let i = 0; i < 10000; i++) {
      data.push({
        key: i,
        name: `姓名${i}`,
        age: 20 + Math.floor(Math.random() * 30),
        address: `地址信息${i}号`,
      });
    }
    this.setState({ dataSource: data });
  }

  rowRenderer = ({ index, key, style }) => {
    const { dataSource, columns } = this.state;
    const rowData = dataSource[index];
    
    return (
      <div key={key} style={style} className="virtual-table-row">
        <div className="virtual-table-cell">{rowData.key}</div>
        {columns.slice(1).map(column => (
          <div key={column.key} className="virtual-table-cell">
            {rowData[column.dataIndex]}
          </div>
        ))}
      </div>
    );
  };

  render() {
    const { dataSource, height, rowHeight } = this.state;
    
    return (
      <List
        width={800}
        height={height}
        rowCount={dataSource.length}
        rowHeight={rowHeight}
        rowRenderer={this.rowRenderer}
      />
    );
  }
}

// 使用示例
const columns = [
  { title: 'ID', dataIndex: 'key', key: 'key' },
  { title: '姓名', dataIndex: 'name', key: 'name' },
  { title: '年龄', dataIndex: 'age', key: 'age' },
  { title: '地址', dataIndex: 'address', key: 'address' },
];

export default () => <VirtualTable columns={columns} />;

方案二:分页加载

分页是最简单直接的优化方式,通过限制每次渲染的数据量,减少 DOM 节点数量。

实现方式:

  1. 使用 Ant Design 的 Pagination 组件

  2. 后端配合实现分页接口,前端传递页码和每页条数

代码示例:

import React, { useState, useEffect } from 'react';
import { Table, Pagination, Button } from 'antd';

const PaginatedTable = () => {
  const [dataSource, setDataSource] = useState([]);
  const [loading, setLoading] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(50);
  const [total, setTotal] = useState(0);

  const columns = [
    { title: 'ID', dataIndex: 'id', key: 'id' },
    { title: '姓名', dataIndex: 'name', key: 'name' },
    { title: '年龄', dataIndex: 'age', key: 'age' },
    { title: '地址', dataIndex: 'address', key: 'address' },
  ];

  // 模拟加载数据
  const fetchData = async (page, size) => {
    setLoading(true);
    try {
      // 模拟API请求延迟
      await new Promise(resolve => setTimeout(resolve, 500));
      
      // 模拟生成数据
      const data = [];
      const start = (page - 1) * size;
      const end = start + size;
      for (let i = start; i < end; i++) {
        data.push({
          id: i + 1,
          name: `用户${i + 1}`,
          age: 20 + Math.floor(Math.random() * 30),
          address: `城市${i + 1}区街道${i + 1}号`,
        });
      }
      
      setDataSource(data);
      setTotal(10000); // 假设总共有10000条数据
    } catch (error) {
      console.error('加载数据失败:', error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData(currentPage, pageSize);
  }, [currentPage, pageSize]);

  const handlePageChange = (page, size) => {
    setCurrentPage(page);
    setPageSize(size);
  };

  return (
    <div>
      <Table
        columns={columns}
        dataSource={dataSource}
        loading={loading}
        pagination={false} // 隐藏默认分页
        bordered
      />
      <Pagination
        current={currentPage}
        pageSize={pageSize}
        total={total}
        onChange={handlePageChange}
        onShowSizeChange={handlePageChange}
        showSizeChanger
        showQuickJumper
        showTotal={(total, range) => `第 ${range[0]}-${range[1]} 条/共 ${total} 条`}
        style={{ marginTop: 16, textAlign: 'right' }}
      />
    </div>
  );
};

export default PaginatedTable;

方案三:懒加载与无限滚动

对于需要连续浏览大量数据的场景,可以实现无限滚动,当用户滚动到页面底部时自动加载更多数据。

实现思路:

  1. 监听表格容器的滚动事件

  2. 判断是否滚动到底部

  3. 加载下一页数据并追加到现有数据中

代码示例:

import React, { useState, useEffect, useRef } from 'react';
import { Table } from 'antd';

const InfiniteScrollTable = () => {
  const [dataSource, setDataSource] = useState([]);
  const [loading, setLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [page, setPage] = useState(1);
  const containerRef = useRef(null);

  const columns = [
    { title: 'ID', dataIndex: 'id', key: 'id' },
    { title: '姓名', dataIndex: 'name', key: 'name' },
    { title: '年龄', dataIndex: 'age', key: 'age' },
    { title: '地址', dataIndex: 'address', key: 'address' },
  ];

  // 模拟加载数据
  const loadMoreData = async () => {
    if (loading || !hasMore) return;
    
    setLoading(true);
    try {
      // 模拟API请求延迟
      await new Promise(resolve => setTimeout(resolve, 500));
      
      // 模拟生成数据
      const newData = [];
      const pageSize = 50;
      const start = (page - 1) * pageSize;
      const end = start + pageSize;
      
      for (let i = start; i < end; i++) {
        newData.push({
          id: i + 1,
          name: `用户${i + 1}`,
          age: 20 + Math.floor(Math.random() * 30),
          address: `城市${i + 1}区街道${i + 1}号`,
        });
      }
      
      setDataSource(prev => [...prev, ...newData]);
      
      // 假设总共只有2000条数据
      if (end >= 2000) {
        setHasMore(false);
      } else {
        setPage(prev => prev + 1);
      }
    } catch (error) {
      console.error('加载数据失败:', error);
    } finally {
      setLoading(false);
    }
  };

  // 初始加载
  useEffect(() => {
    loadMoreData();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 监听滚动事件
  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = container;
      // 距离底部100px时开始加载
      if (scrollTop + clientHeight >= scrollHeight - 100 && hasMore && !loading) {
        loadMoreData();
      }
    };

    container.addEventListener('scroll', handleScroll);
    return () => container.removeEventListener('scroll', handleScroll);
  }, [hasMore, loading]);

  return (
    <div 
      ref={containerRef} 
      style={{ height: '500px', overflow: 'auto', border: '1px solid #e8e8e8' }}
    >
      <Table
        columns={columns}
        dataSource={dataSource}
        loading={loading && dataSource.length === 0}
        pagination={false}
        bordered
      />
      {loading && dataSource.length > 0 && (
        <div style={{ textAlign: 'center', padding: '16px' }}>
          加载中...
        </div>
      )}
      {!hasMore && dataSource.length > 0 && (
        <div style={{ textAlign: 'center', padding: '16px', color: '#999' }}>
          没有更多数据了
        </div>
      )}
    </div>
  );
};

export default InfiniteScrollTable;

方案四:优化表格配置

除了上述三种主要方案外,还可以通过一些配置优化来提升表格性能:

1. 固定列优化

如果表格有固定列,尽量减少固定列的数量,因为固定列会增加渲染复杂度。

2. 简化列配置

避免在列配置中使用复杂的 render 函数,尽量保持 render 函数简洁。

// 不推荐:复杂的render函数
{
  title: '操作',
  key: 'action',
  render: (text, record) => (
    <div>
      <Button type="link" onClick={() => handleEdit(record)}>编辑</Button>
      <Button type="link" danger onClick={() => handleDelete(record)}>删除</Button>
      <Dropdown overlay={menu} placement="bottomRight">
        <Button type="link">更多</Button>
      </Dropdown>
    </div>
  )
}

// 推荐:简化render函数或使用其他方式
{
  title: '操作',
  key: 'action',
  render: (text, record) => (
    <a onClick={() => handleEdit(record)}>编辑</a>
  )
}

3. 关闭不必要的特性

如果不需要某些特性,可以通过配置关闭:

  • 关闭动画效果:设置 transitionName=""

  • 关闭斑马纹:设置 striped=false

  • 简化表格样式,减少CSS复杂度

4. 使用 rowKey 属性

确保设置了唯一的 rowKey,避免React使用索引作为key导致的性能问题。

<Table
  dataSource={dataSource}
  columns={columns}
  rowKey="id" // 使用唯一标识作为rowKey
/>

总结

针对 Ant Design 3.x Table 大数据量渲染慢的问题,推荐优先考虑以下方案:

  1. 虚拟滚动:适用于需要展示大量数据且需要快速滚动的场景,性能最佳

  2. 分页加载:实现简单,兼容性好,适用于大多数业务场景

  3. 无限滚动:适用于需要连续浏览数据的场景,用户体验较好

在实际应用中,可以根据具体业务需求选择合适的优化方案,也可以组合使用多种方案以达到最佳性能。同时,注意对表格配置进行优化,减少不必要的渲染开销。

Ant Design Table 大数据量优化 虚拟滚动 分页加载 无限滚动

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。