React中useMemo依赖未变但内部回调仍执行的问题
问题核心诱因
useMemo的依赖对比默认采用浅引用相等规则,不会递归对比对象、数组这类引用类型的内部内容:只要依赖项的内存地址和上一次渲染不同,哪怕内部所有字段、元素完全一致,React都会判定依赖发生变化,执行useMemo的回调函数。你场景里的卡片列表数据本身是数组,属于引用类型,天然受这个规则影响。- React Query的默认更新逻辑会触发引用变化:当query发生重取、状态切换(比如加载态切换、后台自动刷新)时,即使接口返回的数据内容和上一次完全相同,如果你关闭了结构共享、或者在取数后做了生成新引用的转换操作,拿到的
data就是全新的内存地址。父组件每次因为React Query状态变更触发重渲染时,把这个新引用传给子组件,自然会被判定为依赖变化。 - 代码本身存在两处明显问题:
- 父组件传参时
props?.cardsResponse?.data?末尾多了多余的?符号,会触发语法解析异常,可能产生意外的传值结果 - 子组件的
useMemo回调没有返回任何渲染内容,执行后得到的VerticalCards是undefined,即使依赖判断正常也无法渲染出列表
- 父组件传参时
修复方案
- 优先从根源稳定数据引用,这是性能最高的方案
- 确保React Query对应query的
structuralSharing配置保持默认开启状态(默认值为true),这个配置会在接口返回新数据时做结构对比,如果内容和旧数据完全一致,会直接复用旧数据的内存地址,不会生成新引用。 - 不要在给子组件传prop的位置直接写会生成新引用的inline操作,比如数组展开
[...data]、data.map()、data.filter()这类操作,要提前在父组件用useMemo包裹处理逻辑,保证输出结果的引用在输入不变时保持稳定。 - 删掉父组件传参时末尾多余的
?,修正传参语法:<VerticalCardsList verticalCardsData={props?.cardsResponse?.data} />
- 确保React Query对应query的
- 补全子组件
useMemo的逻辑,在回调内返回完整的卡片渲染结果:export const VerticalCardsList = (props : VerticalCardsProps) => { const VerticalCards = useMemo(() => { console.log('Executing the useMemo function') // 补充卡片渲染的计算逻辑和JSX返回 return props.verticalCardsData?.map(card => ( <VerticalCardItem key={card.id} cardInfo={card} /> )) }, [props.verticalCardsData]) return <div className="vertical-card-container">{VerticalCards}</div> } - 如果业务场景确实无法保证数据引用稳定,再考虑使用深比较方案(不推荐优先使用,大列表场景下深比较的性能开销可能超过重渲染的开销):可以用深比较版本的useMemo替换原生useMemo,或者用
React.memo包裹子组件,传入自定义的深比较函数判断props是否变化。
内容的提问来源于stack exchange,提问作者africandrogba
相关产品推荐
相关产品推荐

