【问题标题】:Callback doesn't receive the updated version of state even when it fires well after state changes回调不会收到状态的更新版本,即使它在状态更改后很好地触发
【发布时间】:2020-12-09 16:33:20
【问题描述】:

我正在使用功能组件。我知道setColor 会异步更改color 的值。但是,我的回调函数没有收到color(蓝色)的更新版本,即使它在color 更新后执行良好也是如此。这是我的代码的抽象版本:

let [color, setColor] = useState("red");

useEffect(() => {
  setColor("blue");
  setTimeout(() => {
    console.log(color);
  }, 5000)
}, []);

(这里是一个沙盒:https://codesandbox.io/s/falling-cherry-17ip2?file=/src/App.js)

我唯一的猜测是setColor 函数几乎创建了一个新的color 变量,而console.log 被困在引用旧的color。


疑难解答

  1. 我知道辅助useEffect 有可能在状态更改时执行我的回调。但是,这很不方便,因为我正处于复杂逻辑的中间,我只希望回调在某些条件下执行。

  2. 我也知道useRef 变量会立即更新,因此这是一个替代方案。


尽管如此,问题仍然存在:为什么没有记录 color 的更新值以及我可以在主 useEffect 中做些什么来访问最新版本的 color 状态?

【问题讨论】:

  • 你想达到什么目的?
  • 它已更新为蓝色,但正如昆汀在他的回答中解释的那样,当 setTimeout 被实例化时,您正在记录渲染中的状态值。只需将 console.log 移出 useEffect 即可。

标签: javascript reactjs react-hooks


【解决方案1】:
  1. setColor 改变状态。
  2. 阶段的变化使函数组件再次执行
  3. 函数组件的新调用重新运行let [color, setColor] = useState("red");
  4. 这会将color 的当前状态分配给color 变量。
  5. 时间流逝
  6. 传递给setTimeout 的箭头函数运行。这有 closed over previous color 变量,它被分配了 old 状态。

【讨论】:

  • 谢谢@Quentin 我刚刚更新了 sn-p 以在 useEffect 末尾包含空数组,我忘了包含。对于那个很抱歉。我做了一个沙盒。如果您能再看一下这个问题,将不胜感激
  • @tonitone120 — 这没什么区别。
  • 感谢@Quentin。虽然回答我的问题可能并不重要,但大概是在useEffect 完成之后对函数组件 (FC) 的新调用,这里?
  • 我真的不确定时机。您传递给 useEffect 的函数将在那时完全定义。
【解决方案2】:

这是一个 sn-p 在不同时间记录color 状态值,并在 useEffect 返回时显示清理的效果。它只是用来说明昆汀在他们的回答中列出的时间表。

const App = ()=>{
  const [color, setColor] = React.useState("red");
  
  console.log('outside: ', color);
  
  React.useEffect(() => {
    setColor("blue");
    console.log('inside: ', color);
    setTimeout(() => {
      console.log('inside-timed: ', color);
    }, 5000)
    
    // the cleaned-up timer won't fire
    const timer = setTimeout(() => {
      console.log('timer: ', color);
    }, 5000)

    return (clearTimeout(timer));
  },[])
  
 return (
  <div style={{backgroundColor: color, width: '40px', height: '40px'}} ></div>
 )
}

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

【讨论】:

    猜你喜欢
    • 2021-07-26
    • 2021-12-25
    • 2019-05-07
    • 1970-01-01
    • 2017-01-24
    • 2021-09-29
    • 2023-01-26
    • 2021-07-03
    • 1970-01-01
    相关资源
    最近更新 更多