React中使用useState时如何避免无关状态变更引发的列表重渲染?
解决方案
问题根本原因
React组件只要自身状态、接收的props、绑定的context发生变更,就会触发整个组件的全量重渲染。你当前的列表渲染逻辑直接写在App组件内部,count是App的内部状态,count更新时App组件会整体重渲染,列表的map逻辑自然会重新执行,触发不必要的计算。
具体实现方案
核心思路是把列表模块抽为独立组件,配合React.memo做渲染缓存,只有当列表依赖的repos属性发生变化时,才会触发列表组件的重渲染。
改造步骤
- 拆分独立的RepoList组件,用
React.memo包裹,组件只接收repos作为入参 - 把原App组件中列表渲染的逻辑迁移到RepoList组件中
- App组件中只需要把repos作为属性传递给RepoList即可
改造后完整代码
import "./styles.css"; import { Fragment, useEffect, useState, memo } from "react"; // 拆分独立列表组件,用memo包裹做渲染缓存 const RepoList = memo(({ repos }) => { return ( <div className="App"> {repos.map((r) => { console.log("render"); return <li key={r.id}>{r.name}</li>; })} </div> ) }) const App = () => { const [repos, setRepos] = useState([]); const [count, setCount] = useState(1); useEffect(() => { const fetchRepos = async () => { const response = await fetch("https://api.github.com/repositories"); const repoDetails = await response.json(); console.log(repoDetails); setRepos([...repoDetails]); }; fetchRepos(); }, []); const handleCount = () => { setCount(count + 1); }; return ( <Fragment> <RepoList repos={repos} /> <button onClick={handleCount}>Button {count}</button> </Fragment> ); }; export default App;
补充说明
如果后续需要给RepoList传递回调函数作为属性,需要配合useCallback缓存回调函数,避免因为回调引用变化导致memo缓存失效。
内容的提问来源于stack exchange,提问作者vaibhav
相关产品推荐
相关产品推荐

