Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
useRefがレンダリング間でミュータブルな値を保持し、直接DOMアクセスを提供する方法。
useRefはコンポーネントの全ライフタイムを通じて持続するミュータブルなオブジェクト { current: value } を返します。stateと異なり、ref.currentを変更しても再レンダリングはトリガーされません。ReactはrefsをDOMへの直接アクセスのためのエスケープハッチとしても使用します — コミットフェーズ後、Reactはref.currentを実際のDOMノードに設定し、ブラウザAPIへの命令的なアクセスを提供します。
最初のレンダリングで、useRef(initialValue)はオブジェクト'{' current: initialValue '}'を作成し、FiberのHooksリストに格納します。その後のすべてのレンダリングで、Reactは同じオブジェクトを返します — ref.currentは常に同じボックスを指します。
ReactはRef.currentの変更を追跡しません。ref.current = 5と書いても、Reactはそれが変わったことを知らず、再レンダリングをスケジュールしません。これにより、refsは表示する必要はないが持続させたい値に最適です。
refをJSX要素に渡すとき(<input ref='{'myRef'}' />)、Reactはレンダーフェーズ中にref.currentを設定しません。コミットフェーズ — DOMノードが存在した後 — まで待ち、その後ref.current = domNodeを設定します。
コンポーネントがアンマウントされると、Reactはクリーンアップエフェクトを実行する前にref.current = nullを設定します。これによりエフェクトがデタッチされたDOMノードにアクセスするのを防ぎます。
デフォルトでは、refsを関数コンポーネントにアタッチできません。forwardRefを使用してref propを受け入れ、DOMエレメントに転送するか、useImperativeHandleを通じて命令的なメソッドを公開してください。
refオブジェクト。Reactはすべてのレンダリングで同じオブジェクトを渡します。currentを自由に変更できます — 再レンダリングは発生しません。
refをJSX要素に渡すと、コミット後にref.currentで基になるDOMノードを取得できます。フォーカス、スクロール、測定に便利です。
ref propを受け入れて内側の要素に転送するか、useImperativeHandleを通じて公開するために関数コンポーネントをラップします。
親が子のrefにアクセスするときに見えるものをカスタマイズします。DOMノードの代わりに特定のメソッドを公開できます。
UIに影響する値(再レンダリングをトリガー)にはstateを使用します。レンダリングに影響しない値(タイマー、DOMノード、以前の値、フラグ)にはrefを使用します。
1// 1. DOM access — focus an input programmatically2const inputRef = useRef(null);3<input ref={inputRef} />4// After mount: inputRef.current is the <input> DOM node5inputRef.current.focus(); // imperative DOM call67// 2. Persist a value without re-rendering8const timerRef = useRef(null);9timerRef.current = setInterval(tick, 1000);10// Later:11clearInterval(timerRef.current);1213// 3. Read latest state in a stale closure14const countRef = useRef(count);15countRef.current = count; // sync on every render16useEffect(() => {17 const interval = setInterval(() => {18 console.log(countRef.current); // always latest value19 }, 1000);20 return () => clearInterval(interval);21}, []); // empty deps — no stale closure problem
RefsはReactが命令的なコードのために公式に提供するエスケープハッチです。ReactのDeclarativeな世界と、命令的な呼び出しが必要なブラウザAPI(フォーカス、スクロール、アニメーション、サードパーティDOMライブラリ)を橋渡しします。また、エフェクト内の古いクロージャ問題も解決します — 最新のstateとrefを同期させることで、長期実行の非同期操作内で安全に現在の値にアクセスできます。
A multi-step checkout form should automatically focus the first empty field when the user navigates to a new step. Using state to track focus causes infinite re-renders.
Attempting to manage focus with useState creates a loop: setState triggers re-render, re-render re-focuses, which fires onFocus, which might set state again. Focus is an imperative DOM operation — it doesn't fit React's declarative model.
Use a ref to directly call `.focus()` on the input DOM node: `useEffect(() => { inputRef.current?.focus() }, [currentStep])`. The ref gives you direct DOM access without triggering re-renders. Focus management is inherently imperative — refs are React's bridge to imperative DOM APIs.
Takeaway: Use refs for imperative DOM operations that don't produce visual output (focus, scroll, measure, select text, play/pause media). These operations are side effects that bypass React's virtual DOM — refs give you a controlled escape hatch.
You need to compare the current value with the previous value to show a 'price changed' animation. Storing the previous value in state causes an extra re-render on every change.
Using `useState(previousPrice)` to track the old price means: price changes → re-render with new price → useEffect sets previousPrice → ANOTHER re-render. Two renders for one price change, and the animation triggers late.
Use a ref: `const prevPriceRef = useRef(price)`. In useEffect, compare `price !== prevPriceRef.current`, trigger the animation, then update: `prevPriceRef.current = price`. Refs update without re-rendering — you get the comparison for free, no extra render cycle.
Takeaway: Refs are the correct tool for 'instance variables' — values that need to persist across renders but shouldn't trigger re-renders when updated. Common patterns: previous values, timer IDs, DOM nodes, external library instances, and accumulator values.