Chapter 2 of 4
Creating and Using Context
The three pieces: create, provide, consume.
A context is created once at module level, provided somewhere near the top of the tree, and read anywhere below.
// theme-context.js
import { createContext, useContext } from "react";
const ThemeContext = createContext("light");
export function ThemeProvider({ value, children }) {
return (
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}// App.jsx
<ThemeProvider value={theme}>
<Layout />
</ThemeProvider>
// Any component below, at any depth
function NavButton() {
const theme = useTheme();
return <button className={theme}>Menu</button>;
}The default value
The argument to createContext is used only when a component reads the context with no matching provider above it. It is a fallback, not an initial value.
const UserContext = createContext(null);
export function useUser() {
const value = useContext(UserContext);
if (value === null) {
throw new Error("useUser must be used inside a UserProvider");
}
return value;
}Wrapping the provider in a hook
Exporting a useTheme hook rather than the raw context gives you one place to add validation, defaults or logging later, and stops the context object leaking across your codebase.
Nested providers
A component reads the nearest provider above it, so nesting lets a subtree override the value.
<ThemeProvider value="light">
<Page /> {/* light */}
<ThemeProvider value="dark">
<Sidebar /> {/* dark */}
</ThemeProvider>
</ThemeProvider>