即使在状态更改后很好地触发回调,它也不会收到状态的更新版本

IT技术 javascript reactjs react-hooks
2022-07-17 02:14:33

我正在使用功能组件。我知道异步setColor更改的值。color但是,我的回调函数没有收到color(blue) 的更新版本,即使它在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状态?

2个回答
  1. setColor改变状态。
  2. stage的变化使得Function Component再次执行
  3. 函数组件的新调用重新运行let [color, setColor] = useState("red");
  4. 这将当前状态分配给color变量color
  5. 时间流逝
  6. 传递给setTimeout运行的箭头函数。这已经关闭了分配状态先前变量。 color

这是一个记录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>