如何在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
相关产品推荐
相关产品推荐

