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

如何在useEffect中使用setInterval更新状态时阻止List组件重渲染

问题

我拥有List.js和Counter.js两个组件,在App.js中实现了两个需求:

  • DOM渲染完成后通过setInterval每秒触发计数递增并展示
  • 列表仅在手动点击提交按钮时更新

但当前存在问题:每次count状态更新时,List组件也会随之重新渲染,需要让List仅在item状态更新时才渲染。

App.js代码如下:

export default function App() {
  const addtolist = useRef();
  const [item, setItem] = useState([]);
  const [count, setCount] = useState(0);

  useEffect(() => {
     let timer = setInterval(() => {
       setCount((count) => count + 1);
     }, 1000);
     return () => {
       clearInterval(timer);
     };
  }, []);

  const submitHandler = () => {
    setItem((item) => [...item, addtolist.current.value]);
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input type="text" name="addtolist" ref={addtolist} />
      <button onClick={submitHandler}>Submit</button>
      <Counter count={count} />
      <List data={item} />
    </div>
  );
}
解决方案

核心方案:用React.memo包裹List组件

React的React.memo高阶组件可以缓存组件,仅当组件的props发生变化时才重新渲染。修改List.js,用React.memo导出组件即可:

import React from 'react';

const List = ({ data }) => {
  // 你的List组件渲染逻辑
  return (
    <ul>
      {data.map((item, idx) => (
        <li key={idx}>{item}</li>
      ))}
    </ul>
  );
};

// 包裹后,只有当data的引用变化时才会重新渲染List
export default React.memo(List);

原理说明:

  • 每次点击提交按钮时,我们通过[...item, addtolist.current.value]生成新数组,data的引用发生变化,List会重新渲染
  • 当count更新时,List接收的props(data)没有变化,React.memo会跳过List的重新渲染

可选优化:拆分计数器组件(缩小渲染范围)

如果想进一步减少App组件的渲染频率,可以把计数器相关的状态和逻辑拆成独立组件,让count的更新只影响自身组件树:

// 新建CounterWrapper.js
import React, { useState, useEffect } from 'react';
import Counter from './Counter';

export default function CounterWrapper() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <Counter count={count} />;
}

然后在App.js中替换原有的计数器部分:

// App.js中导入CounterWrapper
import CounterWrapper from './CounterWrapper';

// ...其他代码不变
return (
  <div className="App">
    {/* ...其他元素不变 */}
    <CounterWrapper />
    <List data={item} />
  </div>
);

这样count的状态更新只会触发CounterWrapper和Counter的重新渲染,App组件不会因为count变化而重新渲染,进一步优化性能。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 21:25:16