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

useContext触发onClick时出现多余渲染与表格重复行问题求助

问题解决:React Context引发表格重复新增行的问题

核心原因分析

你的表格行数翻倍的本质问题是数据被重复加载并追加,而非单纯的Context重渲染。当setRowData触发App组件重渲染时,Table组件会随之重新执行,如果你的数据加载逻辑(比如请求后端数据)没有限制执行时机,就会每次重渲染都重新拉取数据并追加到现有列表中,导致行数不断累加。同时,原Context的Provider每次渲染都会创建新的value对象,会触发所有订阅组件的不必要重渲染,加重了这个问题。


解决方案步骤

1. 优化Context Provider,避免不必要的重渲染

修改App.js,用useMemo缓存Context的value对象,只有当rowData变化时才重新生成:

import { createContext, useState, useMemo } from 'react';
import { Routes, Route } from 'react-router-dom';
// 导入你的组件:Dashboard、Table、DetailsPage、UserSettings

export const vesselContext = createContext();

const App = () => {
  const [rowData, setRowData] = useState();

  // 用useMemo缓存上下文值,仅在rowData变化时更新
  const contextValue = useMemo(() => ({
    rowData,
    setRowData
  }), [rowData]);

  return (
    <vesselContext.Provider value={contextValue}>
      <Routes>
        <Route path='/dashboard' element={<Dashboard />} />
        <Route path='/table' element={<Table />} />
        <Route path='/table/details' element={<DetailsPage/>} />
        <Route path='/settings' element={<UserSettings />} />
      </Routes>
    </vesselContext.Provider>
  );
}

export default App;

2. 修复Table组件的数据加载逻辑,确保只加载一次

修改Table组件,限制数据加载仅在组件挂载时执行一次,并且直接覆盖数据而非追加:

import { useContext, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { vesselContext } from './App';

const Table = () => {
  const { setRowData } = useContext(vesselContext);
  const [tableData, setTableData] = useState([]);
  const navigate = useNavigate();

  // 仅在组件首次挂载时加载数据
  useEffect(() => {
    // 模拟后端数据请求
    const fetchTableData = async () => {
      // 替换为你的实际数据请求逻辑
      const res = await fetch('/api/table-data');
      const data = await res.json();
      // 直接设置数据,而非追加
      setTableData(data);
    };
    fetchTableData();
  }, []); // 空数组依赖,确保只执行一次

  const passData = (event, row) => {
    setRowData(row);
    // 跳转到详情页
    navigate('/table/details');
  };

  return (
    <div>
      {/* 假设你的表格组件结构 */}
      <table>
        <tbody>
          {/* 务必使用唯一key,避免DOM复用异常 */}
          {tableData.map(row => (
            <tr key={row.id}>
              <td>{row.name}</td>
              <td>
                <button onClick={(event) => passData(event, row)}>查看详情</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default Table;

关键注意点

  • 数据加载逻辑:绝对不要在组件渲染流程中直接执行数据请求,必须放在useEffect中,并通过依赖项控制执行时机。如果之前是用setTableData(prev => [...prev, newData])这种追加方式,改成直接覆盖即可。
  • 组件key:渲染表格行时必须使用唯一的key(如数据的id字段),避免React复用DOM元素导致的异常渲染。
  • Context性能:用useMemo缓存上下文值可以减少订阅组件的不必要重渲染,虽然不是行数增加的直接原因,但能优化整体性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:45:47