refs
useImperativeHandle
Customizes the value a parent gets when it attaches a ref to your component, exposing only a curated imperative API. Reach for it when a parent legitimately needs to call methods like focus(), scrollTo(), or play() on a child.
useImperativeHandle(ref, () => handle, dependencies?) Parameters & Behavior
| Parameter | Purpose |
|---|---|
| ref | The ref forwarded from the parent (via forwardRef, or a ref prop in React 19) |
| createHandle | Function that returns the object the parent will see on ref.current |
| dependencies | Optional deps — the handle is rebuilt only when a dep changes |
| curated surface | Expose named methods instead of leaking the raw DOM node |
Examples
const Input = forwardRef((props, ref) => {
const inner = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => inner.current.focus(),
clear: () => { inner.current.value = ''; }
}), []);
return <input ref={inner} {...props} />;
}); Parent gets { focus, clear } instead of the raw DOM node
const parentRef = useRef(null);
parentRef.current.focus(); Calling into the curated API from the parent
useImperativeHandle(ref, () => ({ play: () => video.current.play(), pause: () => video.current.pause() }), []); Video wrapper exposing only play/pause controls
useImperativeHandle(ref, () => ({ scrollToItem: (i) => list.current.scrollToOffset({ offset: i * ITEM_HEIGHT }) }), []); List component exposing an imperative scroll helper
Gotcha
Overusing this hook signals leaky abstractions — prefer declarative props first. Forgetting deps causes the handle to close over stale values.
Related hooks
useRef
Returns a mutable object whose .current property persists for the lifetime of the component without triggering re-renders on change. Reach for it to hold DOM nodes, timers, previous values, or any imperative handle that render output does not depend on.
useLayoutEffect
Runs a side effect synchronously after DOM mutations but before the browser paints. Reach for it only when you need to measure the DOM and then mutate it in a way the user must never see mid-flight (e.g. tooltip positioning).
useCallback
Returns a memoized version of a callback whose identity stays stable until a dependency changes. Reach for it when passing callbacks to memoized children (React.memo) or as dependencies of other hooks that would otherwise re-run on every render.