Examples

Canonical small patterns: controlled state, derived data, list rendering with keys, and data fetching with cleanup.

Path: examples

Third-party documentation. This is independently authored analysis of the public React codebase — not the official docs, and not reviewed or endorsed by the React team.

Examples

Canonical small patterns, each deliberately minimal. Production code composes these into custom hooks rather than repeating them inline.

Lifting state for shared UI

Two inputs reflecting one value hold that value in their common parent and receive it via props with a setter callback — "lifting state up" remains the first tool for shared state before reaching for context or stores.

Derived data without state

Values computable from props/state (const completed = todos.filter(t => t.done).length) are computed during render, not stored in state — duplicated state is the root of most "UI shows stale data" bugs.

List rendering

Map items to elements with stable keys from data identity (ids), never indices, so reconciliation preserves instance state across reorderings and removals.

Subscribing to external stores

useSyncExternalStore(subscribe, getSnapshot) is the sanctioned bridge between React and non-React state (browser APIs, third-party stores) — it handles tearing-free reads during concurrent renders that naive useState + effect bridges get wrong.

Custom hooks as composition units

Any combination of the above becomes a function named useSomething; components then read like declarative compositions of capabilities rather than accumulations of boilerplate.

Examples

A controlled input

A controlled input
typescript
function SearchBox({ onSearch }) {
const [query, setQuery] = useState('');
 
return (
<form onSubmit={(e) => { e.preventDefault(); onSearch(query); }}>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
</form>
);
}
STATUSexample

The input's value is driven by state; every keystroke re-renders with new state. This inversion — UI as a function of state — is React's central pattern.

Fetching data with cancellation

Fetching data with cancellation
typescript
function Profile({ userId }) {
const [user, setUser] = useState(null);
 
useEffect(() => {
let ignore = false;
fetchUser(userId).then((u) => { if (!ignore) setUser(u); });
return () => { ignore = true; };
}, [userId]);
 
return user ? <h1>{user.name}</h1> : <p>Loading…</p>;
}
STATUSexample

The effect re-runs when userId changes and its cleanup marks stale results as ignorable — the standard guard against out-of-order responses in race-prone fetching.

Edge Cases

  • State updates are batched and asynchronous: reading state immediately after calling its setter returns the old value within the same event pass.
  • Keys must be stable identities within a list — array indices as keys cause state to attach itself to the wrong item when items reorder or are removed.
  • Effects with missing dependencies capture stale closures; exhaustive-deps linting exists because the correct dependency array is usually not the one that silences the warning.