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を渡すと、無限ループが発生します。
ステートフルコンポーネントを使用する実用的なソリューションがありますが、機能コンポーネントを使用してこれを実現したい
対処する必要がある主な問題は 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'));