🙌
useRefでフラグを保持する
React フロントでは useRef をフラグ代わりに使う場面が多いので、その振る舞いをサンプルで整理しておきます。
useRef とは?
- React が提供する "箱"。
useRef(initialValue)で箱を作ると、ref.currentに好きな値を入れられる。 - コンポーネントが何度レンダー(描画)されても、同じ箱が再利用される。だから値がリセットされない。
- 値を変えても画面が再レンダーされない。副作用のフラグや最新 DOM の参照に向いている。
レンダーとは?
React コンポーネントの関数が呼ばれ、JSX から DOM を組み立て直すこと。setState や親から受け取る props が変わるとレンダーが起きて、関数本体が再実行される。useRef はその再実行に巻き込まれないので値を保持できる。
サンプルで見る useRef
import { useRef, useState } from "react";
export function SubmitButton() {
const isSubmittingRef = useRef(false);
const [result, setResult] = useState("未送信");
const handleClick = async () => {
if (isSubmittingRef.current) {
return; //ボタン連打を効かなくしてる
}
isSubmittingRef.current = true; // フラグ ON
setResult("送信中...");
await fakeRequest();
//...1.5秒後
setResult("完了!");
isSubmittingRef.current = false; // フラグ OFF
};
return (
<button onClick={handleClick} disabled={isSubmittingRef.current}>
{result}
</button>
);
}
async function fakeRequest() {
return new Promise((resolve) => setTimeout(resolve, 1500));
}
-
isSubmittingRefはレンダーをまたいでも同じオブジェクト。setResultで再レンダーが走っても、isSubmittingRef.currentの真偽値は保持される。 -
disabled属性には ref の値をそのまま渡しているけれど、setResultによる再レンダーで最新値が UI に反映される。
ref.current で何を参照できる?
- 自前のフラグや最新の値(例:外部 API のレスポンスキャッシュ)
- DOM 要素
- ID など再レンダーで消したくない値
フラグで使うときの注意
-
画面更新が必要なら state と組み合わせる
ref だけ更新しても UI は変わらない。上の例のように、見た目を変えるときはuseStateや親コンポーネントの props で描画を司る。 -
同じ ref を複数コンポーネントで共有しない
コンポーネント外の変数に置いてしまうと、インスタンス間で値が混ざる。必要ならカスタムフックで包んでスコープを閉じる。 -
同期タイミングを意識する
setTimeout内で ref を読むときは、最新レンダーで更新した値が入っているか確認。useEffectのクリーンアップで OFF にしておくと安全。
useRef は「レンダーではリセットされないけれど、更新しても再レンダーを引き起こさない」ユニークな箱。フラグ管理や外部リソースの参照先として使うと、余計な state や再レンダーを増やさずに済むのでおすすめです。
Discussion