Note ref.current is null during the first render and gets assigned after the DOM node mounts. Never read or write ref.current during rendering -- only inside effects or event handlers.
dom refuseReffocus inputaccess domdom element reference
Mutable Values (No Re-render)
syntax
const valueRef = useRef(initialValue);
valueRef.current = newValue; // does NOT trigger re-render
Note useRef is like an instance variable for function components. Updating .current does not cause a re-render. Use it for values you need to persist across renders without triggering UI updates: timer IDs, previous values, flags.
mutable refpersist valueno re-renderprevious valueinstance variablestore value across renders
Note In React 19, ref is passed as a regular prop to function components. forwardRef is no longer necessary and is considered deprecated. Existing code using forwardRef still works but should be migrated over time.
forward refref as propforwardRefpass ref to childexpose dom node
Callback Refs
syntax
<element ref={(node) => {
// node is the DOM element or null on unmount
}} />
example
function MeasuredBox() {
const [height, setHeight] = useState(0);
const measureRef = (node) => {
if (node !== null) {
setHeight(node.getBoundingClientRect().height);
}
};
return (
<div>
<div ref={measureRef} style={{ padding: '20px' }}>
<p>This box has dynamic content.</p>
<p>Its height is measured via a callback ref.</p>
</div>
<p>Measured height: {height}px</p>
</div>
);
}
Note Callback refs fire whenever the ref attaches or detaches. In React 19, callback refs can return a cleanup function that runs when the element is removed, similar to useEffect cleanup. Useful for measuring elements or integrating third-party DOM libraries.
Note useImperativeHandle restricts what the parent can access through the ref. Expose only the methods the parent needs instead of the entire DOM node. Combine with ref-as-prop in React 19 (no forwardRef needed).
useImperativeHandleexpose methodscustom ref handleimperative apiparent control child
Note Store timer IDs in a ref so they survive re-renders without causing them. Always clear the timer on unmount via useEffect cleanup to prevent firing after the component is gone.
store timer iddebouncetimeout refclear timeoutpersist between renders