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

useEffect在深层对象属性变更时未触发问题求助

问题根源

React的useEffect默认对依赖项做浅比较,也就是只对比引用地址。你当前的问题大概率是修改sourceArray时直接操作了原数组/原对象的属性,修改后仍把原引用传给setSourceArray,导致React认为状态未发生变更,子组件拿到的groups引用始终不变,自然无法触发useEffect。

解决方案

第一步:修正状态更新逻辑(优先推荐)

遵循React状态更新的不可变原则,每次修改都返回全新的引用,修改后的数组和原数组引用地址不同,此时原有写法的useEffect可直接触发。
示例更新逻辑:

const funcToChangeObj = () => {
  // 1. 浅拷贝整个数组生成新引用
  const changedArray = [...sourceArray]
  // 2. 找到需要修改的数组项,同样浅拷贝生成新引用
  const targetItem = {...changedArray[0]}
  // 3. 深层属性修改同样遵循不可变原则,比如修改children
  targetItem.children = [...targetItem.children, {name: '新节点', id: '2'}]
  // 4. 把修改后的项放回新数组
  changedArray[0] = targetItem
  // 5. 传入新数组更新状态
  setSourceArray(changedArray)
}

修改完成后原有组件的useEffect就可以正常触发:

function MyComponent({ groups }) {
    useEffect(() => {
        // 业务逻辑
    }, [groups])
}

第二步:无需修改引用的深比较方案(可选)

如果业务场景确实无法每次更新都生成新的顶层引用,可以自己实现支持深比较的useEffect,不需要引入第三方库:

import { useEffect, useRef, useState } from 'react';
// 深比较函数,普通的对象/数组可以用该实现,存在循环引用、函数、Symbol等类型时可替换为lodash.isEqual
function deepEqual(a, b) {
  try {
    return JSON.stringify(a) === JSON.stringify(b)
  } catch(e) {
    return false
  }
}

// 自定义深比较useEffect
function useDeepEffect(callback, dependencies) {
  const prevDeps = useRef(dependencies);
  const [trigger, setTrigger] = useState(0);
  // 每次渲染都对比深层值,值变化时更新触发器
  if (!deepEqual(prevDeps.current, dependencies)) {
    prevDeps.current = dependencies;
    setTrigger(prev => prev + 1);
  }
  useEffect(callback, [callback, trigger]);
}

在组件中使用:

function MyComponent({ groups }) {
  useDeepEffect(() => {
    // 业务逻辑
  }, [groups])
}

之前方案失效原因

  • useRef方案:你的useEffect依赖仍然是groups,如果groups引用未发生变化,useEffect完全不会执行,内部的isEqual判断逻辑根本没有运行的机会,自然无效。
  • 第三方深比较库方案:大概率是你的状态更新时未改变引用,库拿到的前后值是同一个引用,就算深比较也会认为没有变化,或者库的使用方式不符合要求。

内容的提问来源于stack exchange,提问作者Jeppe Christensen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:15:03