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

如何在React严格模式下正确结合useState与useEffect?

解决React严格模式下useConst Hook的重复执行问题

我编写了一个Hook,用于一次性生成值,并可在组件卸载时(可选)清理该值:

function useConst(fn, cleanup) {
  const [value] = useState(fn);

  useEffect(
    () => () => {
      cleanup?.(value);
    },
    [value]
  );
  return value;
}

但这个Hook在React严格模式下无法正常工作——副作用会执行两次。我尝试过基于useRef和useMemo的变体,但它们在严格模式下同样失效。

问题根源

React严格模式在开发环境中会刻意重复执行组件的挂载/卸载流程,用来检测潜在的资源泄漏或逻辑问题:

  • useState的初始化函数fn会被调用两次(React会忽略第二次的返回值,保留首次结果)。
  • useEffect的清理函数会在模拟卸载时执行一次,待组件重新挂载后,真正卸载时又执行一次,导致清理逻辑被重复触发。
  • useRef/useMemo的实现方案要么会让fn重复执行,要么无法避免清理逻辑的重复触发。

修复方案

以下是适配严格模式的useConst实现,确保fn只执行一次,且清理逻辑仅在真正的组件卸载时触发:

function useConst(fn, cleanup) {
  const valueRef = useRef(null);
  const mountCount = useRef(0);

  // 仅在首次挂载时执行值生成逻辑
  if (mountCount.current === 0) {
    valueRef.current = fn();
  }

  useEffect(() => {
    mountCount.current += 1;
    return () => {
      mountCount.current -= 1;
      // 仅当挂载次数归0(真正卸载)时执行清理
      if (mountCount.current === 0 && cleanup) {
        cleanup(valueRef.current);
        valueRef.current = null; // 可选:重置引用,避免内存泄漏
      }
    };
  }, [cleanup]);

  return valueRef.current;
}

方案说明

  • 用mountCount跟踪组件挂载次数,确保值生成函数fn仅在组件首次挂载时执行,严格模式下的重复挂载不会重新生成值。
  • 清理逻辑仅在挂载次数归0时触发,规避了严格模式下模拟卸载导致的重复清理问题,同时保证生产环境正常卸载时的清理逻辑生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 15:33:32