You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用useMemo与useEffect优化React Table数据加载及行选中编辑

优化重渲染与实现选中行可编辑

一、减少不必要的重渲染

1. 优化useFetch钩子

  • 修复异步逻辑:避免混用await和.then(),改用try/catch统一处理错误
  • 添加请求取消机制:使用AbortController防止组件卸载后仍更新状态,避免内存泄漏
  • 移除无效的console.log(data):状态更新是异步操作,此处打印的始终是旧值

修改后的useFetch:

export const useFetch = url => {
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await axios.get(url, { signal });
        setData(response.data);
        setError(null);
      } catch (err) {
        if (!signal.aborted) {
          setError(err);
        }
      } finally {
        if (!signal.aborted) {
          setLoading(false);
        }
      }
    };

    fetchData();
    return () => controller.abort();
  }, [url]);

  return { data, error, loading };
};

2. 记忆化处理列配置

在Users组件中,使用useMemo缓存列配置,仅当data变化时重新生成,避免每次渲染都创建新的columns数组触发DataTable重渲染:

const columns = useMemo(() => {
  if (!data || data.length === 0) return [];
  return Object.keys(data[0]).map(key => ({
    Header: key.toLocaleUpperCase(),
    accessor: key
  }));
}, [data]);

3. 记忆化DataTable组件

用React.memo包裹DataTable,仅当columns或data变化时才重新渲染:

export default React.memo(DataTable);

二、实现选中行可编辑

1. 创建可编辑单元格组件

新建EditableCell.jsx,支持在编辑模式和展示模式间切换:

import React, { useState } from 'react';

const EditableCell = ({ cell: { value }, row, column: { accessor } }) => {
  const [isEditing, setIsEditing] = useState(false);
  const [inputValue, setInputValue] = useState(value);

  const handleSave = () => {
    // 此处可添加更新数据的API调用逻辑
    console.log(`更新${accessor}为${inputValue},行数据:`, row.original);
    setIsEditing(false);
  };

  return (
    <td>
      {isEditing ? (
        <>
          <input
            type="text"
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
          />
          <button onClick={handleSave}>保存</button>
          <button onClick={() => setIsEditing(false)}>取消</button>
        </>
      ) : (
        <span onClick={() => setIsEditing(true)}>{value}</span>
      )}
    </td>
  );
};

export default EditableCell;

2. 修改DataTable组件

  • 获取选中行数据:从useRowSelect返回的selectedFlatRows中提取选中行ID
  • 记忆化选中行ID集合:避免每次渲染都重新创建集合
  • 条件渲染单元格:仅当行被选中时,渲染可编辑单元格

修改后的DataTable关键部分:

import EditableCell from './EditCell';
import React, { useMemo } from 'react';

const DataTable = ({ columns, data }) => {
  // ...其他代码不变

  const {
    // ...其他属性
    selectedFlatRows,
  } = tableInstance;

  // 记忆化选中行ID
  const selectedRowIds = useMemo(() => {
    return new Set(selectedFlatRows.map(row => row.id));
  }, [selectedFlatRows]);

  // ...其他代码不变

  return (
    // ...其他代码不变
    <tbody {...getTableBodyProps()}>
      {page.map((row, idx) => {
        prepareRow(row);
        const isSelected = selectedRowIds.has(row.id);

        return (
          <tr {...row.getRowProps()}>
            {row.cells.map((cell, idx) => (
              <td {...cell.getCellProps()}>
                {isSelected ? (
                  <EditableCell cell={cell} row={row} column={cell.column} />
                ) : (
                  cell.render('Cell')
                )}
              </td>
            ))}
          </tr>
        );
      })}
    </tbody>
    // ...其他代码不变
  );
};

export default React.memo(DataTable);

这些更改后,重渲染次数会减少到合理范围(初始渲染→加载中→数据加载完成),且只有选中的行会变为可编辑状态。

内容的提问来源于stack exchange,提问作者Shyam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 10:54:17