【React】 useEffectで描画後に処理を実行
useEffect
を用いると、そのコンポーネントがレンダリングされた後に実行したいコードを書くことができます。副作用フックと呼ばれます。
目次
useEffectしなかったときのよくある失敗
学び始めたばかりの頃によくあるのが、一度だけ実行したいものとして、普通に処理を書くパターンです。
export default function App() { const [x, setX] = useState(10); const addValue = () => { setX(x + 5); }; // 一度だけ実行したい処理 const hoge = "..."; // ... return ( // ... ); }
しかし、これではうまくいきません。コンポーネントの関数は、useしている値が更新されるなどが起こると、関数全体を実行し直すためです。全体が実行し直されるので、上のような書き方をするとその度に何度も実行されるということになってしまいます。
useEffectの実行のタイミング
useEffect
に入れた処理は、レンダリング後とアンマウント後(指定したときのみ)に実行されます。つまり
export default function App() { const [x, setX] = useState(10); // 初回と、xを更新してレンダリングされた後に実行 const addValue = () => { setX(x + 5); }; return ( <div> <p>{x}</p> <button onClick={addValue}>addValue</button> </div> ); }
のreturn
まで終わり、更に描画も完了した後に実行される、ということになります。useしている値を更新するなどした際にもレンダリングされるため、その度にuseEffect
に入れた関数が実行されます。
レンダリングが終わった後なので、DOMが更新済みの状態で処理が実行されます。
useEffectを使う
宣言
useEffect
には、レンダリング後に実行したい関数を入れます。
import { useEffect, useState } from 'react'; export default function App() { const [x, setX] = useState(10); const addValue = () => { setX(x + 5); }; // 初回レンダリング後と、useした値の更新後に自動で実行 useEffect(() => { // レンダリング後なので、xは更新後の値 document.title = `App | ${x}`; }); return ( // ... ); }
特定の値が変わったときだけ処理
上のコード例では、もしほかにも変化する値があった場合に、関係ない値が変化してもレンダ後に実行されます。しかし、上の例ではx
以外が変化しても再実行する必要はないはずです。
そこで、useEffect
の第2引数に監視する変数を配列で入れます。そうすると監視している変数が変化したときのみ実行されるようになります。
// 最初と、レンダリング後にxが変わっていた時だけ実行 useEffect(() => { document.title = `App | ${x}`; }, [x]);
マウント時だけ処理する
もし最初の1回だけ実行したいものを作る場合、監視対象を空の配列にすることで、マウント時以外実行しないようにします。
// [] なので、何が変化しても再実行しない useEffect(() => { document.title = `App | Home`; }, []);
無限ループに注意
もしuseEffect
内で監視対象の値を変更した場合、その変更がトリガーとなってまた実行されます。
useEffect(() => { setX(x + 1); }, [x]);
この例では、x
を監視対象にしていますが、
x
が更新されるuseEffect
に入れた関数が実行される- その中で
x
が更新される - これによって
useEffect
に入れた関数が実行される
のようにして無限ループします。この例では対象を指定しているので分かりやすいですが、
useEffect(() => { setX(x + 1); });
のように第2引数を省略した場合は全てが監視対象となるため、無限ループしやすくなり、注意が必要です。
クリーンアップ
そのコンポーネントが消えるとき (アンマウントされるとき) に、どのような後処理を行うかを書くことができます。
クリーンアップ用のコードは、useEffect
に入れる関数の戻り値に関数として設定します。
export default function Counter() { const [x, setX] = useState(10); const addValue = () => { setX(x + 5); }; useEffect(() => { document.title = `App | ${x}`; return () => { document.title = "App"; } }, [x]); return ( // ... ); }
このコードでは、x
の値が変わるごとにタイトルを更新し、このコンポーネントがアンマウントされたらタイトルをApp
に戻す、という処理をしています。
クリーンアップが無ければ、アンマウントしても何も起こりません。
まとめ
useEffect
は、マウント時、監視している値の更新時、アンマウント時の3つのタイミングで呼び出されます。マウント時だけ呼びたい場合は、監視対象を無しにすれば実現できるということを覚えておきましょう。
