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

React Hooks useDidUpdateEffect如何实现深度比较避免不必要执行

解决方案

你有两种无需开发新钩子的方案可直接落地,均能解决JSON.stringify键顺序不稳定导致的无效触发问题:

方案1:给现有useDidUpdateEffect增加深度比较可选参数(推荐)

仅需修改现有useDidUpdateEffect的逻辑,新增第三个可选参数控制是否开启深度比较,完全兼容原有调用逻辑,无需调整历史代码:

import { useRef, useEffect } from "react";
import { isEqual } from "lodash";

export default function useDidUpdateEffect(effect, deps, deep = false) {
  const didMount = useRef(false);
  const prevDeps = useRef(deps);

  useEffect(() => {
    if (didMount.current) {
      let needRunEffect = true;
      if (deep) {
        // 开启深度比较时校验依赖是否真实变化
        needRunEffect = !prevDeps.current.every((dep, index) => 
          isEqual(dep, deps[index])
        );
      }
      if (needRunEffect) {
        effect();
      }
    } else {
      didMount.current = true;
    }
    // 更新上一次的依赖缓存
    prevDeps.current = deps;
  }, deps);
}

调用方式如下,直接传入需要监听的复杂对象,无需做JSON序列化:

useDidUpdateEffect(() => {
  usersCache.updateCachedUser(data.id, data);
}, [data], true);

方案2:组件内手动做深度比较(无需修改公共钩子)

如果不想改动公共的useDidUpdateEffect逻辑,可以直接在Context的业务代码里加一层深度比较判断:

import { isEqual } from "lodash";

export function CurrentUserProvider({ children }) {
  const [data, setData] = useStateWithCallback(undefined);
  // 新增ref存储上一次生效的用户数据
  const prevUserDataRef = useRef();

  const updateData = (data, merge = true, callback = undefined) => {
    if (merge) {
      setData((prevData) => ({ ...prevData, ...data }), callback);
    } else {
      setData(data, callback);
    }
  };

  useDidUpdateEffect(() => {
    // 仅当数据真实变化时才执行缓存同步
    if (data?.id && !isEqual(prevUserDataRef.current, data)) {
      usersCache.updateCachedUser(data.id, data);
      prevUserDataRef.current = data;
    }
  }, [data]);

  // ... 其余逻辑不变
}

额外优化兜底

可以给usersCache.updateCachedUser增加幂等判断逻辑:写入前先和缓存中对应id的已有数据做深度比较,如果完全一致则直接返回,不执行写入操作,哪怕上游有无效触发也不会产生额外性能开销。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 20:36:05