🌐
【React】useRef() で初回の2回実行に対応する
背景
React の StrictMode
って、開発環境で useEffect
を2回実行しちゃうんですよね。
('react 純関数'とかでググれば中の話が出てきます)
最初は useState
でフラグを管理してたんですが、「あれ? useRef のほうがよくね?」となったので、この記事を書きました。
useRef とは?
useRef
は React のフックで、ざっくり言うとこんな感じで使えます。
-
DOM 要素への参照を保持(
ref
属性) - コンポーネント間で値を保持(再レンダリングなし)
useEffect
の実行制御(今回のメインテーマ)
基本的な使い方
import { useRef } from "react";
function MyComponent() {
const countRef = useRef(0); // 初期値 0
const increment = () => {
countRef.current += 1;
console.log(countRef.current); // 更新されるけどレンダリングされない!
};
return <button onClick={increment}>Increment</button>;
}
useState
とは違って useRef
の値 (current
) を更新しても コンポーネントは再レンダリングされません。
useEffect の2回実行問題 in StrictMode
React の StrictMode
では、開発環境 (NODE_ENV=development
) で useEffect
の副作用が 2回実行 される仕様になっています。(本番環境では1回だけ)
例えば、こんなコード↓
useEffect(() => {
console.log("Effect 実行!");
sendLoginRequest(); // 2回実行されるかも?
}, []);
これ、本番なら問題ないけど、開発中は2回実行されちゃう。
useRef で StrictMode の2回実行を防ぐ!
この問題を回避するには useRef でフラグを作ってやる のがベスト!
const strictModeIgnoreRef = useRef(false);
useEffect(() => {
if (strictModeIgnoreRef.current) return; // 2回目を防ぐ
strictModeIgnoreRef.current = true;
sendLoginRequest(); // これで1回だけ実行!
}, []);
なぜ useRef を使うのか?
useState
を使うと、値を更新するたびに 再レンダリングが発生 しちゃうんですよね。でも useRef
なら 値を保持しつつ、再レンダリングを防ぐ ことができる!
まとめ
フック | 再レンダリングする? | こんなときに使う! |
---|---|---|
useState |
する | UI に影響を与える値(カウンター、フォーム入力) |
useRef |
しない | DOM 参照、useEffect の実行制御、一時的なフラグ管理 |
useEffect
の2回実行問題に悩んでいるなら、useRef
を試してみたら幸せになれるかも。
Discussion