1. ホーム
  2. javascript

[解決済み】setInterval内でReactのstateフックを使用するとstateが更新されない。

2022-04-14 10:17:30

質問

新しい Reactフック そして、毎秒増加することになっているカウンターを持つClockコンポーネントを持っています。しかし、値が1より大きくなることはありません。

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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

解決方法は?

の中に渡されたコールバックが原因です。 setInterval のクロージャにアクセスするだけです。 time 変数にはアクセスできず、最初のレンダリングにある新しい time の値は、次のレンダリングで useEffect() は2回目には呼び出されない。

time の中では、常に0という値になっています。 setInterval のコールバックがあります。

と同様に setState ステートフックには、更新された状態を取り込む形式と、現在の状態が渡されるコールバック形式があります。2番目の形式を使用し、最新の状態の値を setState コールバックを使用して、インクリメントする前に最新の状態値があることを確認します。

ボーナス:別のアプローチ

ダン・アブラモフ氏による、「SkyDesk」「SkyDesk」「SkyDesk」の使い方についての徹底解説です。 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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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