【问题标题】:React cleanup function doesn't clean state反应清理功能不清理状态
【发布时间】:2020-04-03 09:09:39
【问题描述】:

专家, 请解释一下,为什么在下面的代码中,属性的状态不会在 useEffect 清理函数中被清理?

我的组件:

export default function TestComp() {

  let { id } = useParams();
  const [value, setValue] = useState(null);
  console.log('[TestComp] called...');

  const cleanup = () => {
    console.log('[TestComp] old value', value);
    setValue(null);
  };

  useEffect(() => {
    console.log('[TestComp] id changed: ', id);
    console.log('[TestComp] value in useEffect', value);
    setValue(id);
    return () => {
      cleanup();
    }
  }, [id]);

  return (<React.Fragment>Test id: {id}</React.Fragment>)
}

控制台输出:

[TestComp] called... TestComp.js:8
[TestComp] old value satellites:MTP TestComp.js:11
[TestComp] id changed:  satellites:MTP TestComp.js:16
[TestComp] value in useEffect satellites:FPGA TestComp.js:17
[TestComp] called... 2 TestComp.js:8
[TestComp] old value satellites:FPGA TestComp.js:11
[TestComp] id changed:  satellites:FNE TestComp.js:16
[TestComp] value in useEffect satellites:MTP TestComp.js:17
[TestComp] called... TestComp.js:8

我希望,在第二次调用 useEffect 时,value 将被清理并为 null,但它仍保留旧值:

value in useEffect satellites:MTP TestComp.js:17

提前谢谢你。

【问题讨论】:

  • 它会在你的组件卸载时清理你的状态。基本上如果你想实现componentWillUnmount。比你必须在 useEffect 中返回。更多参考请看这篇文章:daveceddia.com/useeffect-hook-examples
  • 尝试将日志移动到另一个 useEffect 并以 value 作为依赖项

标签: reactjs state use-effect


【解决方案1】:

useEffect 的返回函数只是在应用下一个效果之前清理之前的效果。但是您的代码中的主要问题是

    const cleanup = () => {
    console.log('[TestComp] old value', value);
    setValue(null); // This is not prefer way to use setValue here.
}

通常,在清理期间,我们会取消订阅外部服务/订阅,但在这里您正在更改没有意义的状态,并立即通过运行并在 setValue 之后运行的 useEffect setValue 获取更新 内部清理被调用,这也是再次调用效果的原因,

在你的 useEffect 中添加 setTimeout 后检查你的代码。

`useEffect(() => {
    console.log('[TestComp] id changed: ', id);
    console.log('[TestComp]:Effect value in useEffect', value);
    setValue(id);
    return () => {
      setTimeout(()=> cleanup(), 5000)
    }
  }, [id]);`

可能的解决方案 -

  • 在上述情况下,您使用的是 id,将此属性提升到父组件并将其作为属性传递给 TestComp 组件。

  • 当效果运行时,整个组件会重新渲染,作用域会被破坏,但所有状态都保持在 useState 钩子的闭包内。

working example for above situation

【讨论】:

    【解决方案2】:

    您可能想要添加另一个useEffect,因为在当前情况下,cleanup 函数将仅在 unmount 上运行,这对于当前逻辑非常无用。

    export default function TestComp() {
      let { id } = useParams();
      const [value, setValue] = useState(null);
      console.log('[TestComp] called...');
    
      useEffect(() => {
        console.log('[TestComp] id changed: ', id);
        console.log('[TestComp] value in useEffect', value);
        setValue(id);
    
        /* v Useless cleanup because the component unmounts anyway,
             the `value` state will be cleaned automatically.
        return () => {
          cleanup();
        }
        */
      }, [id]);
    
      // ^ Firstly, the `value` changed on id change
      // v Secondly, the `value` will be reset on `value` change
      useEffect(() => {
        console.log('[TestComp] old value', value);
        setValue(null);
      }, [value]);
    
      return <>Test id: {id}</>;
    }
    

    【讨论】:

      【解决方案3】:

      我认为这是事情发生的顺序问题。

      useEffect 将在调用时“捕获”值作为闭包的一部分,即在调用 TestComp 函数时。当 id 发生变化时,React 会安排调用 cleanup 函数,然后调用 effect。但是 TestComp 直到调用了新的效果函数后才会再次调用。

      您可以在日志中看到这一点,因为来自清理函数的每个 old value 后面紧跟着来自效果函数的 id changed

      而且由于新效果函数“捕获”了调用 TestComp 时的值,因此它不会看到清理函数设置的值。

      另外请注意,至少从测试中我看到 React 抱怨 valuecleanup 不在 useEffect 的依赖项中。

      【讨论】:

        猜你喜欢
        • 2022-01-23
        • 2021-12-24
        • 2018-08-02
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 2018-08-16
        • 1970-01-01
        • 2021-03-24
        相关资源
        最近更新 更多