小编典典

React-UseState-为什么setTimeout函数没有最新状态值?

reactjs

最近我正在研究React Hooks,陷入一个问题/疑问?

下面是重现该问题的基本实现,在这里,我只是flag在单击按钮时切换(状态)变量。

  const [flag, toggleFlag] = useState(false);
  const data = useRef(null);
  data.current = flag;

  const _onClick = () => {
    toggleFlag(!flag);
    // toggleFlag(!data.current); // working

    setTimeout(() => {
      toggleFlag(!flag); // does not have latest value, why ?
      // toggleFlag(!data.current); // working
    }, 2000);
  };

  return (
    <div className="App">
      <button onClick={_onClick}>{flag ? "true" : "false"}</button>
    </div>
  );

我想出了一些其他方法来克服此问题,例如使用useRef或useReducer,但这是正确的吗?或者是否有其他方法只能通过useState解决此问题?

另外, 如果有人解释为什么我们在setTimeout中获得旧的state值这将非常有帮助

沙盒网址-https:
//codesandbox.io/s/xp540ynomo


阅读 1280

收藏
2020-07-22

共1个答案

小编典典

这归结为闭包在JavaScript中的工作方式。给定的函数将从初始渲染中setTimeout获取flag变量,因为flag它不会发生突变。

您可以改为将函数作为参数toggleFlag。此函数将获取正确的flag值作为参数,并且此函数返回的值将替换状态。

const { useState } = React;



function App() {

  const [flag, toggleFlag] = useState(false);



  const _onClick = () => {

    toggleFlag(!flag);



    setTimeout(() => {

      toggleFlag(flag => !flag)

    }, 2000);

  };



  return (

    <div className="App">

      <button onClick={_onClick}>{flag ? "true" : "false"}</button>

    </div>

  );

}



ReactDOM.render(<App />, document.getElementById("root"));


<script src="https://unpkg.com/react@16/umd/react.development.js"></script>

<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>



<div id="root"></div>
2020-07-22