You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中useMemo依赖未变但内部回调仍执行的问题

问题核心诱因
  • useMemo的依赖对比默认采用浅引用相等规则,不会递归对比对象、数组这类引用类型的内部内容:只要依赖项的内存地址和上一次渲染不同,哪怕内部所有字段、元素完全一致,React都会判定依赖发生变化,执行useMemo的回调函数。你场景里的卡片列表数据本身是数组,属于引用类型,天然受这个规则影响。
  • React Query的默认更新逻辑会触发引用变化:当query发生重取、状态切换(比如加载态切换、后台自动刷新)时,即使接口返回的数据内容和上一次完全相同,如果你关闭了结构共享、或者在取数后做了生成新引用的转换操作,拿到的data就是全新的内存地址。父组件每次因为React Query状态变更触发重渲染时,把这个新引用传给子组件,自然会被判定为依赖变化。
  • 代码本身存在两处明显问题:
    • 父组件传参时props?.cardsResponse?.data?末尾多了多余的?符号,会触发语法解析异常,可能产生意外的传值结果
    • 子组件的useMemo回调没有返回任何渲染内容,执行后得到的VerticalCards是undefined,即使依赖判断正常也无法渲染出列表
修复方案
  • 优先从根源稳定数据引用,这是性能最高的方案
    1. 确保React Query对应query的structuralSharing配置保持默认开启状态(默认值为true),这个配置会在接口返回新数据时做结构对比,如果内容和旧数据完全一致,会直接复用旧数据的内存地址,不会生成新引用。
    2. 不要在给子组件传prop的位置直接写会生成新引用的inline操作,比如数组展开[...data]、data.map()、data.filter()这类操作,要提前在父组件用useMemo包裹处理逻辑,保证输出结果的引用在输入不变时保持稳定。
    3. 删掉父组件传参时末尾多余的?,修正传参语法:
      <VerticalCardsList verticalCardsData={props?.cardsResponse?.data}  />
      
  • 补全子组件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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 15:15:48