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

React定时拉取数据场景下,如何仅重渲染变化的Station组件

如何避免React中Station组件的不必要重渲染

问题根源

每次从接口拉取数据后,你直接用新数组替换了stationsData状态,而新数组里的每个stationDataObj都是全新的对象引用——哪怕内容和之前完全一致,React也会认为Station组件的props发生了变化,从而触发所有Station的重渲染。

最优解决方案

我们可以通过组件缓存+精准数据对比来解决这个问题,分两步实现:


1. 用React.memo缓存Station组件

React.memo会对组件的props进行浅比较,只有当props真正变化时才会重新渲染组件。直接包裹Station组件:

// 改造Station组件,添加React.memo缓存
const Station = React.memo(({ stationData }) => {
  return (
    <div>
      <div>{stationData.Name}</div>
      <div>{stationData.Status}</div>
      <div>{stationData.updateTime}</div>
    </div>
  );
});

但这里有个问题:如果每次接口返回的stationData都是新对象(即使内容和旧数据完全一致),浅比较会认为props变化了,依然会触发重渲染。这时候需要自定义比较逻辑。


2. 自定义props比较函数(可选,针对对象内容不变但引用变化的场景)

给React.memo传入第二个参数,精准对比stationData的实际内容:

// 自定义比较函数,只对比站点的关键属性
const areStationPropsEqual = (prevProps, nextProps) => {
  const prev = prevProps.stationData;
  const next = nextProps.stationData;
  
  return (
    prev.Name === next.Name &&
    prev.Status === next.Status &&
    prev.updateTime === next.updateTime
  );
};

// 用自定义比较函数缓存Station组件
const Station = React.memo(({ stationData }) => {
  return (
    <div>
      <div>{stationData.Name}</div>
      <div>{stationData.Status}</div>
      <div>{stationData.updateTime}</div>
    </div>
  );
}, areStationPropsEqual);

3. 优化数据更新逻辑(可选,进一步减少状态变化)

在更新stationsData时,复用未变化的站点对象引用,只替换真正有更新的对象:

useEffect(() => {
  const fetchStationsData = async () => {
    const response = await fetch(`/stationsInfo`);
    const newData = await response.json();

    // 对比新旧数据,复用未变化的对象引用
    const updatedData = stationsData.map(oldStation => {
      const matchedNewStation = newData.find(s => s.Name === oldStation.Name);
      if (!matchedNewStation) return oldStation;

      // 内容完全一致则复用旧对象,否则用新对象
      if (
        oldStation.Status === matchedNewStation.Status &&
        oldStation.updateTime === matchedNewStation.updateTime
      ) {
        return oldStation;
      }
      return matchedNewStation;
    });

    // 加入新增的站点
    const newStations = newData.filter(station => 
      !stationsData.some(old => old.Name === station.Name)
    );

    setStationsData([...updatedData, ...newStations]);
    handleStationsDataChange();
  };

  fetchStationsData();
  const fetchInterval = setInterval(fetchStationsData, intervalTime * 1000);

  return () => clearInterval(fetchInterval);
}, [stationsData]); // 加入stationsData依赖,避免闭包导致的旧数据问题

额外补充:工具栏统计实现

在DisplayStations组件中直接计算状态统计即可:

function DisplayStations() {
  const [stationsData, setStationsData] = useState([]);
  
  // 计算运行/暂停的站点数量
  const runningCount = stationsData.filter(s => s.Status === 'Run').length;
  const holdingCount = stationsData.filter(s => s.Status === 'Hold').length;
  
  // ...其他逻辑
  
  return (
    <Box>
      {/* 顶部工具栏 */}
      <div className="toolbar">Running: {runningCount}, Holding: {holdingCount}</div>
      
      {/* 站点列表 */}
      {stationsData.map((station) => (
        <Station key={station.Name} stationData={station} />
      ))}
    </Box>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 01:15:26