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

使用React useEffect钩子时如何检测依赖项中的对象是否发生变更

问题根因

useEffect的依赖对比默认是引用相等比较,如果每次调用useFetch时传入的param都是新生成的对象(比如父组件直接写useFetch({ page: 1, size: 10 }),每次渲染都会创建新的对象引用),就会被判定为依赖变更,反复触发effect逻辑,最终形成无限循环。

可行解决办法
  • 方法1:把对象属性拆解为基本类型依赖
    如果param的属性是固定可枚举的,可以直接把依赖项替换为对象的各个基础类型属性,避免对对象整体做引用对比:
const useFetch = (param?: { page?: number; size?: number }) => {
  const [count, setCount] = useState<string>("");

  useEffect(() => {
    // 发起数据请求
    setCount("1");
  }, [param?.page, param?.size]) // 拆解为基础类型属性作为依赖

  return count;
}

同时父组件调用时也可以尽量传单个基础类型参数,减少对象传参的场景。

  • 方法2:对对象做深比较判断是否变更
    如果param的结构不固定,没法拆解属性,可以使用useDeepCompareEffect代替原生useEffect,内部会对依赖做深值对比,引用不同但值相同的对象不会触发effect:
    你可以自己封装一个简易的深比较版本:
import { isEqual } from 'lodash';
import { useEffect, useRef } from 'react';

const useDeepCompareEffect = (callback: () => void, dependencies: any[]) => {
  const ref = useRef<any[]>([]);
  // 深对比前后依赖是否一致
  if (!isEqual(dependencies, ref.current)) {
    ref.current = dependencies;
  }
  useEffect(callback, [ref.current]);
}

// 业务中使用
const useFetch = (param?: object) => {
  const [count, setCount] = useState<string>("");

  useDeepCompareEffect(() => {
    // 发起数据请求
    setCount("1");
  }, [param])

  return count;
}

注意如果是自己实现深比较,要注意循环引用等边界场景,避免出现性能问题。

  • 方法3:稳定对象引用
    如果参数不需要频繁变更,可以在父层用useMemo缓存param对象,保证引用不变,只有当属性真正变更时才更新引用:
// 父组件调用侧
const Parent = () => {
  const [page, setPage] = useState(1);
  // 缓存param,只有page变化时才生成新对象
  const fetchParam = useMemo(() => ({
    page,
    size: 10
  }), [page]);

  const data = useFetch(fetchParam);
  return <div>{data}</div>
}
性能注意点

深比较本身有额外性能开销,如果对象层级很深、属性很多,优先选择拆解依赖或者稳定引用的方案,尽量不要高频使用深比较hook。

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

相关产品推荐
方舟 Agent Plan

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

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