React父组件传HTML DOM类型children导致子组件无状态变更时重渲染,如何规避?
问题原因
React.memo 默认对组件的props做浅比较,仅当所有props的引用/值都和上一次渲染相等时,才会跳过子组件重渲染。
你的场景中:
- Test1的
InsideChild没有传入任何props,浅比较一直相等,所以不会触发额外重渲染 - Test2的
InsideChild传入了HTML结构作为children,当父组件OutsideParent因count状态变更重渲染时,JSX中写的<p>children as html dom will not trigger rerender.</p>每次都会生成新的React元素对象,children这个prop的引用每次都不同,React.memo浅比较判定props发生变更,就会触发子组件重渲染。
规避方案
- 方案1:用
useMemo缓存静态children
对于完全静态的children内容,可以用useMemo包裹,依赖项设为空数组,确保其引用在父组件重渲染时保持不变:const OutsideParent = () => { const [count, setCount] = useState(0) // 缓存静态children,仅组件首次渲染时生成一次 const staticChildren = useMemo(() => <p>children as html dom will not trigger rerender.</p>, []) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> <div> Test1: <InsideChild /> </div> <div> Test2: <InsideChild> {staticChildren} </InsideChild> </div> </div> ) } - 方案2:将静态内容定义在组件外部
如果children内容完全不需要依赖父组件的任何状态/属性,可以直接将其定义在父组件外面,全局只会生成一次引用:// 定义在组件外部,引用固定 const staticChildren = <p>children as html dom will not trigger rerender.</p> const OutsideParent = () => { const [count, setCount] = useState(0) // 其余代码不变,直接传入staticChildren即可 } - 方案3:自定义
React.memo比较函数(不推荐)
你可以给React.memo传入第二个自定义比较函数,自行判断props是否相等,但如果children结构复杂,深比较会带来额外的性能损耗,仅在children结构非常简单的场景下可以考虑:const InsideChild = React.memo(({children}) => { const countRef = useRef(0) countRef.current += 1 return <div>render count: {countRef.current} {children}</div> // 自定义比较逻辑,这里假设children内容固定,直接返回true表示props无变更 }, (prevProps, nextProps) => true)
内容的提问来源于stack exchange,提问作者KevinHu
相关产品推荐
相关产品推荐

