Context and shared state
Share values across a tree with Context, but only for data that is genuinely global.
- Create a context and export a provider plus a custom hook.
- Wrap only the subtree that actually needs the value.
- Give consumers a clear default so a missing provider fails loudly.
- Reach for a state library when the data is not really global.
In plain English
Context lets a component share a value with a whole subtree without passing props through every level. You create a context with createContext, wrap a tree in a provider that supplies the value, and read it with useContext. A custom hook wraps the context read so components do not import the context directly. Context is the wrong tool for values that change constantly or belong to only one small branch, because it re-renders every consumer.
Step by step
- 1Decide what single value the whole subtree needs.
- 2Create the context with a type and a null default.
- 3Build a provider that owns the state and passes it down.
- 4Export a custom hook that reads the context and throws without a provider.
import { createContext, useContext, useState, type ReactNode } from 'react'
type Theme = 'light' | 'dark'
type ThemeContextValue = {
theme: Theme
toggle: () => void
}
const ThemeContext = createContext<ThemeContextValue | null>(null)
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<Theme>('light')
function toggle() {
setTheme((current) => (current === 'light' ? 'dark' : 'light'))
}
return <ThemeContext.Provider value={{ theme, toggle }}>{children}</ThemeContext.Provider>
}
export function useTheme(): ThemeContextValue {
const value = useContext(ThemeContext)
if (value === null) {
throw new Error('useTheme must be used within a ThemeProvider')
}
return value
}Common mistakes
- Storing rapidly changing data in Context causes every consumer to re-render on each change.
- Exporting the raw context object lets consumers read it without a provider and get a confusing null.
- Using Context for a value a single component could own locally adds indirection with no benefit.
- Putting unrelated values into one context means the whole tree re-renders whenever any of them changes.
Add a useTheme hook
Create a context with a null default, a provider that supplies a theme, and a useTheme hook that throws when the provider is missing.
import { createContext, useContext } from 'react'
const ThemeContext = createContext<string | null>(null)When is Context the wrong tool?
Make it yours.
Keep a private note for this lesson, then turn the key ideas into flashcards you can revisit.
Lock in what you just learned.
Mark this lesson complete to save your place and move one step closer to the certificate.