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

React useEffect组件卸载时输出旧变量值的问题咨询

React useEffect卸载时获取旧状态值的问题解决

问题根源:闭包陷阱

你遇到的是React闭包陷阱导致的问题:
父组件的doSomething函数会在每次父组件渲染时重新创建,它会捕获当前渲染周期的names状态值。而子组件中绑定卸载逻辑的useEffect依赖项是空数组[],意味着它只会在组件挂载时创建一次清理函数,这个清理函数捕获的是父组件初始渲染时传入的doSomething——该版本的函数里names还是初始值BOB,后续哪怕names更新,旧的doSomething里的names不会同步变化,所以卸载时打印的是旧值。

你之前尝试在子组件维护childNames状态的方法之所以失效,是因为每次names变化都会触发childNames更新,导致useEffect依赖项变更,React会在组件重新渲染时先执行上一次的清理函数,最终变成每次输入都触发doSomething,不符合仅卸载时触发的需求。


解决方案

方案1:用useCallback包裹父组件的doSomething

通过useCallback让doSomething仅在names变化时重新创建,同时子组件的useEffect依赖项加上doSomething,确保卸载时调用的是最新版本的函数。

父组件修改:

const ParentComponent = () => {
  const [names, setNames] = useState('BOB');
  const childRef = useRef(null);

  // 用useCallback包裹,依赖names
  const doSomething = useCallback(() => {
    console.log('Did something with the names:' + names)
  }, [names]);

  return (
    <>
      <Text>The names: {names}</Text>
      <ChildComponent
           doSomething={doSomething}
           names={names}
           setNames={setNames}
           ref={childRef}
      />
    </>
  );
};

子组件修改:

// Do something on willUnmount
React.useEffect(() => {
  return () => {
    doSomething();
  };
}, [doSomething]); // 新增doSomething作为依赖

方案2:父组件用ref保存最新names

用ref跟踪names的最新值,让doSomething直接读取ref的当前值,无需修改子组件。

父组件修改:

const ParentComponent = () => {
  const [names, setNames] = useState('BOB');
  const namesRef = useRef(names);
  const childRef = useRef(null);

  // 同步最新names到ref
  useEffect(() => {
    namesRef.current = names;
  }, [names]);

  const doSomething = () => {
    // 读取ref.current获取最新值
    console.log('Did something with the names:' + namesRef.current)
  };

  return (
    <>
      <Text>The names: {names}</Text>
      <ChildComponent
           doSomething={doSomething}
           names={names}
           setNames={setNames}
           ref={childRef}
      />
    </>
  );
};

方案3:子组件用ref保存最新names

在子组件内部用ref跟踪names的最新值,卸载时直接传入该值调用doSomething。

子组件修改:

const ChildComponent = forwardRef((props, ref) => {
  const {doSomething, names, setNames } = props;
  const latestNamesRef = useRef(names);
  const textInputRef = useRef(null); // 修复函数组件不能用this的问题

  // 同步最新names到ref
  useEffect(() => {
    latestNamesRef.current = names;
  }, [names]);

  // Load names to input on mount
  React.useEffect(() => {
    textInputRef.current?.focus();
    textInputRef.current.value = names;
  }, []);

  // Do something on willUnmount
  React.useEffect(() => {
    return () => {
      doSomething(latestNamesRef.current);
    };
  }, []);

  return (
    <View>
       <TextInput
          value={names}
          onChangeText={text => setNames(text)}
          ref={textInputRef}
       />
    </View>
  );
});

父组件对应修改doSomething:

const doSomething = (latestNames) => {
  console.log('Did something with the names:' + latestNames)
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:11:15