पाठ 19 / 25
Refs: DOM Access and Mutable Values
An escape hatch that does not re-render.
useRef for nodes and values
useRef(initial) returns an object whose .current property persists across renders. Two uses: pointing at a DOM node (via the ref attribute) to focus, measure or integrate with non-React code; and storing mutable values (timer ids, previous values, counters) that should not trigger re-renders. Changing ref.current does not update the screen, so do not read refs during rendering for display; use state for anything shown in the UI.
Focusing an input and counting without re-rendering, run
I ran this with React 19.3 and react-dom 19.3 on Node.js 22, compiling JSX with esbuild 0.28. Browser-style examples use jsdom 29 as a fake DOM (imported from a small setup-dom.mjs file) and act() to apply updates. An effect focuses the input via its ref. Three clicks increment a ref counter without re-rendering (still 1 render, label "show 0"); a state update then re-renders and the label shows 3.
import "./setup-dom.mjs"; // test setup: jsdom provides a browser-like DOM in Node
import { useRef, useState, useEffect, act } from "react";
import { createRoot } from "react-dom/client";
let renders = 0;
function Search() {
const inputRef = useRef(null); // points at a DOM node
const clicks = useRef(0); // mutable value that does not trigger renders
const [, force] = useState(0);
renders++;
useEffect(() => { inputRef.current.focus(); }, []);
return <>
<input ref={inputRef} />
<button id="track" onClick={() => { clicks.current++; }}>track</button>
<button id="show" onClick={() => force(x => x + 1)}>show {clicks.current}</button>
</>;
}
const root = createRoot(document.getElementById("root"));
await act(() => root.render(<Search />));
console.log("focused element:", document.activeElement.tagName);
for (let i = 0; i < 3; i++) await act(() => document.getElementById("track").click());
console.log("renders after 3 tracked clicks:", renders, "| label:", document.getElementById("show").textContent);
await act(() => document.getElementById("show").click());
console.log("after re-render label:", document.getElementById("show").textContent);
Output:
focused element: INPUT renders after 3 tracked clicks: 1 | label: show 0 after re-render label: show 3
Refs for things the UI does not show
If a value appears on screen, it belongs in state; refs are for behind-the-scenes values and DOM handles.
त्वरित जाँच: What happens when you change ref.current?
- The page reloads
- The component always re-renders
- React throws an error
- The value changes but the component does not re-render
Answer
The value changes but the component does not re-render — Refs are not reactive.