Context and Composition
Share data across a tree and design flexible component APIs without deep prop chains.
Busque em todas as páginas da documentação
Share data across a tree and design flexible component APIs without deep prop chains.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
createContext defines a channel. The default value is only used when no matching Provider sits above the consumer.
type Theme = "light" | "dark";
const ThemeContext = createContext<Theme>("light");Wrap a subtree with Provider and pass value. Every consumer below re-renders when value identity/content changes.
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);useContext reads the nearest Provider value. Call it in function components or custom hooks only.
function Title() {
const theme = useContext(ThemeContext);
return <h1 data-theme={theme}>Docs</h1>;
}Put frequently changing state in one context and a stable dispatch/setter in another so pure consumers of dispatch do not re-render on every state tick.
const StateCtx = createContext<State | null>(null);
const DispatchCtx = createContext<Dispatch | null>(null);Export a hook that throws if the provider is missing. Call sites get a non-null type without repetitive checks.
function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error("useTheme requires ThemeProvider");
return ctx;
}When the value is an object, memoize it so consumers do not re-render from a new object identity every parent render.
const value = useMemo(() => ({ user, logout }), [user, logout]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;Pass children (and named slots) instead of threading ten props through intermediate layout shells.
function Page({ nav, children }: { nav: React.ReactNode; children: React.ReactNode }) {
return (
<div className="page">
<aside>{nav}</aside>
<main>{children}</main>
</div>
);
}A parent owns state; child subcomponents read it via context so the public API looks like declarative markup.
function Tabs({ children }: { children: React.ReactNode }) {
const [active, setActive] = useState(0);
return (
<TabsCtx.Provider value={{ active, setActive }}>{children}</TabsCtx.Provider>
);
}Outer providers should own broader concerns (auth, theme); inner providers own feature state. Document required order when it matters.
<AuthProvider>
<ThemeProvider>
<App />
</ThemeProvider>
</AuthProvider>End-to-end mini pattern: state, provider, consumer button.
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>("light");
const value = useMemo(() => ({ theme, setTheme }), [theme]);
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}A working default can hide a missing Provider in production. Prefer null defaults plus a throwing hook for required context.
const AuthContext = createContext<Auth | null>(null);Context re-renders all consumers of that context. Split contexts or move state down when only a leaf needs frequent updates.
// Prefer narrow providers near the feature that needs them
<CartProvider>{cartUi}</CartProvider>Named slot props accept pre-built React nodes. Parents control content; children control placement.
function Modal({ title, body, footer }: {
title: React.ReactNode;
body: React.ReactNode;
footer?: React.ReactNode;
}) {
return (
<div role="dialog">
<header>{title}</header>
<div>{body}</div>
{footer && <footer>{footer}</footer>}
</div>
);
}Layout components only arrange children. They stay reusable across pages without knowing page data shapes.
function Center({ children }: { children: React.ReactNode }) {
return <div className="grid place-items-center min-h-full">{children}</div>;
}One app-wide bag of state turns into an invisible prop drill and re-render storm. Colocate providers with the subtrees that need them.
// Feature route owns its provider, not root layout
<Route element={<EditorProvider><EditorPage /></EditorProvider>} />Stack versions: React 19 · TypeScript (strict) · context as a deliberate dependency
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥