React中使用useMemo后子组件仍意外重渲染如何解决
问题根因
点击按钮触发所有子组件重渲染,本质是两个写法问题:
- 父组件每次
items状态更新触发重渲染时,内部的handleClick函数都会重新创建,引用地址每次都不一样 - 子组件错误使用
useMemo缓存渲染结果,useMemo本身是用于缓存计算值的API,无法替代组件级别的重渲染拦截,且因为依赖的handleClick每次都变,缓存直接失效
修复方案
分两步修改即可,修改后只有状态实际变化关联的组件会触发重渲染,核心功能完全保留:
- 父组件用
useCallback包裹handleClick,内部全程使用函数式状态更新,移除对外部items变量的依赖,保证handleClick引用永久稳定 - 子组件移除内部错误的
useMemo写法,改用React.memo包裹组件,实现props不变时跳过重渲染
修正后的父组件代码
import { useState, useEffect, useCallback } from 'react'; import ButtonDiv from './ButtonDiv'; export default function App() { const [items, setItems] = useState([]); const handleClick = useCallback((number) => { setItems((prevState) => { return prevState.includes(number) ? prevState.filter((slot) => slot !== number) : [...prevState, number] }) }, []); useEffect(() => { console.log("items", items); }, [items]); return ( <div className="App"> <ButtonDiv handleClick={handleClick} slot="5" /> <ButtonDiv handleClick={handleClick} slot="10" /> <ButtonDiv handleClick={handleClick} slot="15" /> <ButtonDiv handleClick={handleClick} slot="20" /> <ButtonDiv handleClick={handleClick} slot="25" /> </div> ); }
修正后的子组件代码
import { memo } from 'react'; const ButtonDiv = memo(({ handleClick, slot }) => { console.log("renderButton", slot); return <button onClick={() => handleClick(slot)}>Click me</button>; }); export default ButtonDiv;
补充说明
useCallback依赖数组为空不会导致状态更新拿到旧值:函数式setState的入参prevState永远是最新的状态快照,不需要将items加入依赖,因此handleClick在组件整个生命周期内引用地址不会发生变化- 额外优化建议:当前传入的
slot是字符串类型,如果需要存储数字类型的选中值,可以在传参时直接写slot={5},比较时统一使用严格相等===,避免隐式类型转换带来的潜在问题
内容的提问来源于stack exchange,提问作者Aayush Dahal
相关产品推荐
相关产品推荐

