React HooksのuseEffectが無限ループで実行されて困った経験があります。
一体、useEffectはいつ実行されるのでしょうか?
この記事では、useEffectの実行タイミング3パターンをまとめます。
useEffectの実行タイミング
まずは、useEffectの使い方を簡単にまとめます。
実際に、どのタイムミングで指定した処理が実行されるのか、確認していきましょう。
サンプルを3つ用意したので、動作も見ながらチェックしてください。
1. レンダリング後に実行
See the Pen [React useEffect] Firing an effect after render by amateur-engineer (@amaeng) on CodePen.
import React, { useState, useEffect } from 'react';
export default function UseEffectExample() {
const [count, setCount] = useState(0);
useEffect(() => {
const ele = document.getElementById("txt");
if(ele) {
ele.innerHTML = `You clicked ${count} times`;
}
});
return (
<div>
<p id="txt" />
<button onClick={() => setCount(count + 1)}>
Count up
</button>
</div>
);
}
デフォルト(第二引数を指定しない状態)では、レンダリングした後にuseEffectに指定した処理が実行されます。
サンプル1では、stateのcountが変化すると再レンダリングされるので、その際にuseEffectの処理も実行されます。
(useEffect使わず、直接pタグへテキスト入れたら良いじゃんって思った。でもuseEffectを説明するサンプルなので、そこは許してください…)
2. 値の変更時に実行
See the Pen [React useEffect] Conditionally firing an effect by amateur-engineer (@amaeng) on CodePen.
import React, { useState, useEffect } from 'react';
export default function UseEffectExample() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const [flag, setFlag] = useState(false);
useEffect(() => {
setText(`You clicked ${count} times`);
},[flag]);
return (
<div>
<p>{text}</p>
<button onClick={() => setCount(count + 1)}>
Count up
</button>
<button onClick={() => setFlag(!flag)}>
Update title
</button>
</div>
);
}
第二引数に変数を設定すると、第二引数の変数の値が変更されたタイミングでuseEffectの処理が実行されます。
サンプル2では、booleanのflagを第二引数に指定して、ボタンクリックによるtrue/falseの切り替え時に実行されるようにしています。
第二引数には、変化をチェックしたい変数を配列に入れて指定する必要があります。
3. 初回レンダリング時だけ実行
See the Pen [React useEffect] Firing an effect only once by amateur-engineer (@amaeng) on CodePen.
import React, { useState, useEffect } from 'react';
export default function UseEffectExample() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
useEffect(() => {
setText(`You clicked ${count} times`);
},[]);
return (
<div>
<p>Title is not updated</p>
<p>{text}</p>
<button onClick={() => setCount(count + 1)}>
Count up
</button>
</div>
);
}
第二引数に空の配列を指定すると、初回のレンダリング時のみuseEffectの処理が実行されます。
サンプル3では、初回レンダリング時のみテキストをセットするため、いくら”Count up”のボタンをクリックしてcountの値を変えてもuseEffectの処理は2回目以降実行されません。
最後に注意点
第二引数を指定せずにuseStateのセッターを呼ぶと、useEffectの処理が無限ループします。
例えばこんな感じ。
import React, { useState, useEffect } from 'react';
export default function UseEffectExample() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1)
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Count up
</button>
</div>
);
}
useEffectの処理を実行→countの値が変化→再レンダリング→useEffectの処理を実行….
といった感じで、無限ループの完成です。
気をつけましょう!!
他にもReactHooksの記事を書いてます。
コメント