为什么未关联的useState更新会触发react-window列表重新渲染
问题根因
你遇到的重渲染问题和react-window本身无关,是React组件渲染的基础规则导致的:
- 你将
Row组件定义在了App组件的函数体内部,每次App因为count状态更新触发重渲染时,函数体都会从头执行,Row组件每次都会生成一个全新的函数引用 FixedSizeList接收的children是新的Row实例, React会判定为需要重新渲染整个列表的可见节点,你加的React.memo完全不会生效:memo的作用是同一个组件前后渲染时对比props是否变化,现在组件本身的引用都变了,会直接走新组件的全量渲染流程,不会触发areEqual的对比逻辑
解决方案
方案1:将Row组件移出App组件外部(最推荐)
直接把Row的定义放在App组件外面,保证它的引用永远不会随App渲染变化:
import React, { useState } from "react"; import { FixedSizeList, areEqual } from "react-window"; // 移到组件外部定义 const Row = React.memo(props => { const { index, style } = props; return <div style={style}>Row {index}</div>; }, areEqual); function App() { const [count, setCount] = useState(0); const handleOnClick = () => { console.log("PUSHED ME"); setCount(count+1) } return ( <div className="App"> <FixedSizeList height={200} itemCount={100} itemSize={50} width={'100%'} > {Row} </FixedSizeList> <div onClick={handleOnClick}>点我</div> </div> ); } export default App;
方案2:用useMemo缓存内部的Row组件
如果有特殊场景必须把Row定义在App内部,可以用useMemo缓存Row的引用,避免每次渲染生成新实例:
// App组件内部定义时添加缓存逻辑 const Row = useMemo(() => React.memo(props => { const { index, style } = props; return <div style={style}>Row {index}</div>; }, areEqual), []);
如果你的Row需要用到App内部的状态,可以把相关状态通过props传递给Row,同时把对应状态加到useMemo的依赖数组里,areEqual会自动对比props变化,只有真的需要更新时才会重渲染对应行。
内容的提问来源于stack exchange,提问作者MJey
相关产品推荐
相关产品推荐

