Context — Sharing Without Prop Drilling
IntermediateContext passes a value to a whole subtree without threading props through it. It is a delivery mechanism, not a state manager, and every consumer re-renders when the value changes.
Overview
Context solves one problem: a value needed deep in the tree, passed through components that do not care about it. Theme, session, locale and a feature-flag set are the canonical examples. The trap is treating it as global state, because context has no selector — when the provider's value changes, every consumer re-renders regardless of which part of the value they read. That is fine for a theme that changes twice a session and expensive for state that updates on every keystroke.
The Standard Setup
Provider, a guarded hook, and a value that is not recreated on every render.
const ThemeContext = createContext(null)
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('system')
// Without useMemo this object is new on EVERY render of the
// provider, so every consumer re-renders even if theme is the same
const value = useMemo(
() => ({ theme, setTheme, isDark: theme === 'dark' }),
[theme],
)
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
}
export function useTheme() {
const ctx = useContext(ThemeContext)
if (!ctx) throw new Error('useTheme must be used inside <ThemeProvider>')
return ctx // never undefined from here on
}
// Export the hook, not the context. Consumers then cannot use it
// outside a provider, and you can change the implementation freely.The Re-render Problem
No selectors, so splitting the context is the tool you have.
// One context holding everything
const AppContext = createContext({ user, theme, cart, notifications })
// A component reading only 'theme' re-renders when the cart changes.
// Split by update frequency and by concern
<AuthProvider> {/* changes on sign in/out */}
<ThemeProvider> {/* changes rarely */}
<CartProvider> {/* changes often */}
// Split state from setters, so dispatch-only consumers stay still
const StateCtx = createContext(null)
const ActionsCtx = createContext(null) // this value never changes
// What context is good at:
// theme, locale, current user, feature flags, a form's registry,
// anything a subtree needs and that changes rarely
// What it is bad at:
// high-frequency state, large objects many components slice
// differently — that is what Zustand or Redux selectors are for.Do You Need It At All
Composition removes a surprising amount of prop drilling without any context.
// The problem people reach for context to solve
<Page user={user}>
<Layout user={user}>
<Sidebar user={user}>
<Profile user={user} /> // only this one actually needs it
// Composition — pass the rendered element instead of the data
<Page>
<Layout sidebar={<Sidebar><Profile user={user} /></Sidebar>} />
</Page>
// Layout and Sidebar never mention 'user' at all.
// Two levels of prop drilling is not a problem worth a provider.
// Reach for context at three or more, or when many scattered
// components need the same value.
// Multiple providers stack into a pyramid quickly. Compose them:
function Providers({ children }) {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider><ThemeProvider>{children}</ThemeProvider></AuthProvider>
</QueryClientProvider>
)
}Key Points to Remember
- 1Context delivers a value to a subtree; it is not a state manager and has no selectors
- 2Every consumer re-renders when the provider value changes, so memoise the value object
- 3Split contexts by concern and by update frequency, and separate state from actions
- 4Passing rendered children removes much prop drilling without any context at all
- 5Use context for rarely-changing shared values; use a store for high-frequency state many components slice differently
Interview Questions
Sign in to ask AriaWhy should a context provider memoise its value object?
What is the main performance limitation of context?
How can composition reduce prop drilling without context?
Ask Aria about Context — Sharing Without Prop Drilling
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.