The Context API is React's built-in mechanism for passing data through the component tree without props at every level. This lesson builds production-ready provider patterns for theme, authentication, and configuration.
Building a Context Module
A well-structured context module exports: the context object (often private), a Provider component wrapping state logic, and a custom hook for consumption with error checking.
Avoid exporting raw context — force consumers through your hook for consistent validation and future refactors.
// auth-context.jsx
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, setUser }), [user]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth requires AuthProvider');
return ctx;
}
Memoized value object prevents re-renders when parent re-renders without user change.
Nest multiple providers or combine into one AppProviders component.
Test components with mock providers in tests.
Context Patterns
Common context architecture choices.
Pattern
Use For
Single context
Theme, locale
Split contexts
Auth vs UI preferences
Provider + hook
All production contexts
Default null + throw
Catch missing provider early
Memoized value
Reduce consumer re-renders
AppProviders wrapper
Clean main.jsx
Splitting Contexts
One AuthContext for user session and a separate ThemeContext prevents theme toggles from re-rendering auth-unrelated subtrees when only theme changes — if values are split correctly.
Testing with Providers
Wrap components under test with necessary providers or create test utilities that supply mock context values.