Advanced React APIs & Patterns
Go beyond everyday hooks into transitions, deferred values, imperative handles, portals, external-store subscriptions, reusable abstractions, and advanced component patterns.
Transitions & useTransition
A transition marks updates as non-urgent. This is useful when an urgent interaction, such as typing, should remain responsive while expensive derived content updates.
The transition API also provides pending state so the UI can communicate that the non-urgent update is being prepared.
Use transitions to improve interaction scheduling, not as a substitute for fixing pathological algorithms or unnecessary rendering.
const [isPending, startTransition] = useTransition();
function handleChange(value) {
setInput(value);
startTransition(() => {
setFilter(value);
});
}- Transitions distinguish update priority.
- Keep urgent controls responsive.
- Pending UI should explain meaningful background work.
useDeferredValue
useDeferredValue lets a component receive a lagging version of a value so expensive rendering can be deprioritized.
It is useful when the source value is urgent but a consumer is expensive. The consumer may temporarily render using the previous value while React prepares the new one.
Do not use it to hide broken loading logic. The deferred UI should still communicate that it may be showing older data.
- Deferred values can decouple urgent input from expensive consumers.
- The deferred value may temporarily lag.
- Use it for responsiveness, not correctness.
Imperative Handles
Sometimes a reusable component needs to expose a small imperative API, such as focus(), scrollToTop(), or open(). An imperative handle can expose a controlled interface instead of leaking internal DOM nodes.
Use this sparingly. Declarative props are usually easier to reason about. Imperative APIs are most appropriate for integration with inherently imperative behavior.
useImperativeHandle(ref, () => ({
focus() {
inputRef.current?.focus();
}
}), []);- Prefer declarative APIs when possible.
- Expose narrow imperative capabilities when integration requires them.
- Do not expose internal mutable state unnecessarily.
Portals & Overlay Architecture
Portals render a subtree into a different DOM location while preserving its React relationship. They are commonly used for dialogs, tooltips, menus, and overlays that need to escape clipping or stacking contexts.
Even though the DOM location changes, React context and event relationships follow the React tree. This is useful for building overlays that still belong to the component that controls them.
Accessibility remains your responsibility: focus, labels, keyboard dismissal, and modal semantics must be implemented correctly.
createPortal(
<div role="dialog" aria-modal="true">...</div>,
document.body
);- Portals solve DOM placement problems, not accessibility automatically.
- Context relationships remain based on the React tree.
- Overlays need deliberate focus and keyboard behavior.
Subscribing to External Stores
When React reads data owned by an external store, the subscription must be compatible with React's rendering model. The dedicated external-store subscription API helps React obtain a consistent snapshot and subscribe to changes.
This is particularly relevant to state libraries and applications that integrate existing mutable stores.
The principle is more important than the API name: React needs a reliable snapshot and notification mechanism rather than arbitrary mutable reads during render.
- External store integration needs consistent snapshots.
- Avoid reading mutable external state without a subscription model.
- State libraries should integrate with React's scheduling semantics.
Compound Components & Headless Patterns
Compound components allow several components to cooperate through shared context or controlled state. Examples include Tabs, Accordion, Select, and Menu systems.
A headless component separates behavior and accessibility from visual styling. Consumers provide the presentation while the component manages interaction semantics.
These patterns are powerful but can be overused. If a simple prop-based component solves the problem, prefer the simpler API.
<Tabs>
<Tabs.List>
<Tabs.Tab value="overview">Overview</Tabs.Tab>
<Tabs.Tab value="activity">Activity</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="overview">...</Tabs.Panel>
</Tabs>- Compound components express coordinated behavior.
- Headless components separate behavior from presentation.
- Use advanced patterns when they reduce, rather than increase, consumer complexity.