advanced · 24 minute study
A ref is a stable container; a render is a snapshot
Timers, DOM focus and async callbacks need deliberate decisions about current values, captured values and rendering.
Useful preparation · 1 prerequisite
Use this as a map, not a lock. If these ideas are familiar, continue.
- Effects synchronize with something outside React — Thinking of effects as synchronization prevents loops, stale subscriptions and unnecessary derived-state effects.
First, build a mental model
A ref object persists across renders, and changing ref.current does not request a render. State describes visible UI; refs hold imperative handles or carefully chosen mutable values.
- Use state for values whose change should update the UI.
- Use refs for DOM handles, timer IDs or other imperative resources.
- A closure retains the render's values unless it deliberately reads a current ref.
- A ref is not a universal fix for missing dependencies or confused ownership.
function Search() {
const input = useRef(null);
const [query, setQuery] = useState('');
function focusSearch() { input.current?.focus(); }
return <><button onClick={focusSearch}>Focus search</button>
<label>Search <input ref={input} value={query} onChange={e => setQuery(e.target.value)} /></label></>;
}- State
query is visible data; changing it should rerender.
- Ref
input.current is the current DOM handle after commit.
- Event
The focus button performs an imperative action using that handle.
Production thinking
Take this beyond the example.
Use refs sparingly at imperative boundaries. Test focus restoration, timer cleanup and async callbacks after props/state change.
Sources and further reading
Your evidence
unseen is a local learning signal, not a credential or proof of production competence.
Explain the mental model, then explicitly acknowledge it. Opening a page is not evidence.
Supported retries can complete this lesson. Independent evidence and delayed review determine the skill stage.
Next lesson · Keys tell React which entity keeps its state →