小编典典

在setInterval中使用React状态挂钩时状态未更新

reactjs

我正在尝试新的React Hooks,并有一个带有计数器的Clock组件,该计数器应该每秒增加一次。但是,该值不会增加到超过一。

function Clock() {

  const [time, setTime] = React.useState(0);

  React.useEffect(() => {

    const timer = window.setInterval(() => {

      setTime(time + 1);

    }, 1000);

    return () => {

      window.clearInterval(timer);

    };

  }, []);



  return (

    <div>Seconds: {time}</div>

  );

}



ReactDOM.render(<Clock />, document.querySelector('#app'));


<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>

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



<div id="app"></div>

阅读 621

收藏
2020-07-22

共1个答案

小编典典

原因是传递给setInterval的闭包中的回调仅访问time第一个渲染器中的变量,而无法访问time后续渲染器中的新值,因为useEffect()第二次未调用。

time``setInterval回调中的值始终为0 。

就像setState您熟悉的状态挂钩一样,状态挂钩有两种形式:一种是处于更新状态的状态,另一种是将当前状态传入的回调形式。您应该使用第二种形式,并读取setState回调中的最新状态值以在递增之前,请确保您具有最新的状态值。

奖励:替代方法

Dan Abramov setInterval在他的博客文章中深入探讨了有关使用钩子的主题,并提供了解决此问题的替代方法。强烈建议阅读!

function Clock() {

  const [time, setTime] = React.useState(0);

  React.useEffect(() => {

    const timer = window.setInterval(() => {

      setTime(prevTime => prevTime + 1); // <-- Change this line!

    }, 1000);

    return () => {

      window.clearInterval(timer);

    };

  }, []);



  return (

    <div>Seconds: {time}</div>

  );

}



ReactDOM.render(<Clock />, document.querySelector('#app'));


<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>

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



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