【问题标题】:React: Updated state not reflecting in recursive useCallback反应:更新的状态没有反映在递归 useCallback
【发布时间】:2021-04-23 14:15:49
【问题描述】:

我在一个名为 recursivelyuseCallback 挂钩中递增 foo。但是,递增的foo 不会反映在回调中。

const { useState, useCallback } = React;

const App = () => {
  const [foo, setFoo] = useState(0);

  const recursiveCallback = useCallback(() => {
    // always logs 0
    console.log(foo);

    // incrementing foo
    setFoo(foo + 1);

    setTimeout(() => {
      // recursive call
      recursiveCallback();
    }, 250);
  }, [foo]);

  return <button onClick={recursiveCallback}>Click Me</button>;
}

ReactDOM.render(<App />,document.getElementById('root'));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

【问题讨论】:

  • 您在setTimeout 中使用的recursiveCallback 指的是foo 具有先前值的那个。
  • 嗨 Andrea,请检查更新后的问题并附上注释:)

标签: javascript reactjs typescript redux react-hooks


【解决方案1】:

尝试更改此行

setFoo(foo + 1);

setFoo((foo) => foo + 1);

【讨论】:

  • 虽然您的解决方案不起作用,但您能否分享更多关于您为什么选择功能更新而不是 setFoo 的见解?
【解决方案2】:

在日志和 setter 函数中,foo===0 值上都有一个 closure,要修复它,您需要使用 functional updateuseEffect 进行日志记录:

const { useState, useCallback, useEffect } = React;

const App = () => {
  const [foo, setFoo] = useState(0);

  const recursiveCallback = useCallback(() => {
    setFoo(prev => prev + 1);

    setTimeout(() => {
      recursiveCallback();
    }, 250);
  }, [foo]);

  useEffect(() => {
    console.log(foo);
  }, [foo]);

  return <button onClick={recursiveCallback}>Click Me</button>;
}

ReactDOM.render( < App/> , document.getElementById('root'));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

【讨论】:

  • 嗨丹尼斯,请检查更新后的问题并附上注释:)
  • 再一次,有了注释,您在超时内关闭了recursiveCallback,即使它在useCallback 内,您也无法阻止递归。你所做的看起来像xyproblem.info,你应该发布一个你想要解决的实际问题的问题,而不是试图修复你的解决方案
  • 我完全同意你的看法,@Dennis Vash 先生
  • @DennisVash 理解您的观点并用确切的问题更新了问题。
  • @VinaySharma 再发一个问题...三个人已经回答了原来的问题...
【解决方案3】:
  1. 您应该使用 useEffect()[foo] 依赖项来查看设置状态后的更改。
  2. 更新foo的函数应该是Functional update

如果新状态是使用前一个状态计算的,你可以传递一个 设置状态的函数 该函数将接收以前的值,并返回一个更新的 价值

    // incrementing foo
    setFoo(previousFoo => previousFoo + 1);

注意:如果你没有选择functional update会发生什么?

好吧,如果你选择setFoo(foo + 1);,下一个状态将只有2,之后状态不会改变,useEffect和依赖foo也不受影响。

简而言之,如果你需要一个先前的状态,你必须使用functional update

const { useState, useCallback, useEffect } = React;

const App = () => {
  const [foo, setFoo] = useState(0);

  const recursiveCallback = useCallback(() => {
    // incrementing foo
    //setFoo(foo + 1);
    setFoo(previousFoo => previousFoo + 1);

    setTimeout(() => {
      // recursive call
      recursiveCallback();
    }, 500);
  }, [foo]);

  useEffect(() => {
    console.log(foo);
  }, [foo]);
  
  return <button onClick={recursiveCallback}>Click Me</button>;
}

ReactDOM.render(<App />,document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<div id="root"></div>

【讨论】:

  • 您能否分享更多关于为什么选择功能更新而不是 setFoo 的见解?
  • 我刚刚更新了我的答案,请看看@VinaySharma
  • 首先,避免使用诸如Ok, it's not a big deal :) 之类的短语,因为它对解决方案没有帮助,只会使评论部分膨胀。其次,您更新后的答案If the new state is computed using the previous state, you can pass a function to setState The function will receive the previous value, and return an updated value 回答了如何功能更新的工作原理,而不是为什么您选择了它。
  • 哦不,我必须马上回复你,而不是让你等我。这就是为什么Ok, it's not a big deal :)。无论如何,我刚刚更新了我的答案,请再次检查!!!
  • if you chose setFoo(foo + 1), the next sate will be 2 only 非常模糊,因为下一个状态应该是 1,因为 foo 被初始化为 0。在下面的声明中after that, the state is not changed, useEffect with dependency foo is also not affected as well.没有回答原因为什么状态没有改变,而是陈述了一个已知的事实:)
猜你喜欢
  • 2021-06-13
  • 2020-07-22
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 2022-08-09
  • 2021-11-02
相关资源
最近更新 更多