【React】setIntervalは古いStateを参照する
こんにちは、フリーランスエンジニアの太田雅昭です。
setIntervalは古いStateを参照する
setIntervalは、定期実行を行う関数です。感覚的には、これを使用すると、常に新しいStateを得られると思いがちです。ですがReactでは、useEffect内で起動したIntervalは、その時のStateを参照します。
以下のコードを試してみます。
function App() {
const [count, setCount] = useState(0)
useEffect(() => {
const output = () => console.log(count);
const timer = setInterval(output, 1000);
return () => clearInterval(timer);
}, []);
return <button onClick={() => setCount(prev => prev + 1)}>Count: {count}</button>
}
buttonをクリックすると、countが増えます。さらに初期化時に起動したintervalが、そのcountを参照しています。一見、interlvalは常に新しいcountを得るように見えますが、実際は常に古いcountを参照するため、コンソールには延々と0が出力されます。
依存配列に追加する必要がある
これを解決するには、依存配列にcountを追加する必要があります。
function App() {
const [count, setCount] = useState(0)
useEffect(() => {
const output = () => console.log(count);
const timer = setInterval(output, 1000);
return () => clearInterval(timer);
}, [count]); // <= これ!
return <button onClick={() => setCount(prev => prev + 1)}>Count: {count}</button>
}
これで、countが更新されるたびに、古いIntervalが破棄されるとともに新しいIntervalが起動し、予期した動作になります。