200

私は新しいReact Hooksを試していて、毎秒増加するはずのカウンターを備えた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/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>

4

13 に答える 13

243

その理由は、setIntervalのクロージャーに渡されたコールバックがtime最初のレンダリングでのみ変数にアクセスし、が 2 回目に呼び出されないtimeため、後続のレンダリングで新しい値にアクセスできないためです。useEffect()

timeコールバック内では常に 0 の値を持ちsetIntervalます。

おなじみのようsetStateに、状態フックには 2 つの形式があります。1 つは更新された状態を受け取る形式で、もう 1 つは現在の状態が渡されるコールバック形式です。2 番目の形式を使用して、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>

于 2018-10-27T17:25:13.103 に答える
1
const [seconds, setSeconds] = useState(0);
  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((seconds) => {
        if (seconds === 5) {
          setSeconds(0);
          return clearInterval(interval);
        }
        return (seconds += 1);
      });
    }, 1000);
  }, []);

: これは、useState フックを使用してカウンターを更新およびリセットするのに役立ちます。秒は 5 秒後に停止します。最初に setSecond 値を変更してから、setInterval 内の更新された秒数でタイマーを停止するためです。useEffect として 1 回実行します。

于 2022-02-18T08:16:23.110 に答える