web-dev-qa-db-ja.com

useStateの変数がuseEffectコールバックで更新されない

UseStateおよびuseEffectフックの使用中に問題が発生しました

import { useState, useEffect } from "react";

const counter = ({ count, speed }) => {
    const [inc, setInc] = useState(0);

    useEffect(() => {

        const counterInterval = setInterval(() => {
            if(inc < count){
                setInc(inc + 1);
            }else{
                clearInterval(counterInterval);
            }
        }, speed);

    }, [count]);

    return inc;
}

export default counter;

上記のコードはカウンターコンポーネントであり、小道具でカウントを取得し、incを0で初期化し、countと等しくなるまでインクリメントします。

問題は、0を取得するたびにuseEffectとsetIntervalのコールバックでincの更新された値を取得しないため、incが1としてレンダリングされ、setIntervalが明確にならないことです。私はincがuseEffectとsetIntervalのコールバックを閉じている必要があると思うので、そこにupdate incを取得する必要があるので、それはバグですか?

私の場合、useEffectにsetIntervalを設定しているので、依存関係にincを渡すことはできません(他の同様の質問で提案されています)。依存関係配列にincを渡すと、無限ループが発生します。

ステートフルコンポーネントを使用する実用的なソリューションがありますが、機能コンポーネントを使用してこれを実現したい

7
Abhay Sehgal

対処する必要がある主な問題は Closures であり、プロップに依存する条件での間隔のクリアです。

関数setState内に条件チェックを追加する必要があります:

setInc(inc => (inc < count ? inc + 1 : inc));

また、クリア間隔はアンマウント時に発生するはずです。

条件に応じてclearIntervalを追加する場合(inc < count)、間隔IDと増加した数の参照を保存する必要があります。

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';

const useCounter = ({ count, speed }) => {
  const [inc, setInc] = useState(0);

  const incRef = useRef(inc);
  const idRef = useRef();

  useEffect(() => {
    idRef.current = setInterval(() => {
      setInc(inc => (inc < count ? inc + 1 : inc));
      incRef.current++;
    }, speed);

    return () => clearInterval(idRef.current);
  }, [count, speed]);

  useEffect(() => {
    if (incRef.current > count) {
      clearInterval(idRef.current);
    }
  }, [count]);

  useEffect(() => {
    console.log(incRef.current);
  });

  return inc;
};

const App = () => {
  const inc = useCounter({ count: 10, speed: 1000 });
  return <h1>Counter : {inc}</h1>;
};

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

Edit Q-59017467-DepCounter

0
Dennis Vash