Context API & useReducer
📖 Concept
Context API is React's built-in solution for global state. It provides a way to pass data through the component tree without having to pass props down manually at every level.
The Workflow:
- createContext: Define the context.
- Provider: Wrap your app (or a part of it) and provide the value.
- useContext: Consume the value in any child component.
Combining with useReducer:
For complex global state, the most powerful built-in pattern is to store the dispatch function from useReducer in a Context. This creates a "Redux-lite" system without any external dependencies.
Important Warning: Context is not a state management tool; it's a dependency injection tool. It has one major drawback: whenever the context value changes, all components consuming that context will re-render, even if they only use a small piece of the value.
💻 Code Example
1import React, { createContext, useContext, useReducer } from 'react';23// 1. Define Contexts (Split state and dispatch for better performance)4const AuthStateContext = createContext();5const AuthDispatchContext = createContext();67// 2. Reducer8const authReducer = (state, action) => {9 switch (action.type) {10 case 'LOGIN':11 return { ...state, isAuthenticated: true, user: action.payload };12 case 'LOGOUT':13 return { ...state, isAuthenticated: false, user: null };14 default:15 return state;16 }17};1819// 3. Provider Component20export function AuthProvider({ children }) {21 const [state, dispatch] = useReducer(authReducer, {22 isAuthenticated: false,23 user: null24 });2526 return (27 <AuthStateContext.Provider value={state}>28 <AuthDispatchContext.Provider value={dispatch}>29 {children}30 </AuthDispatchContext.Provider>31 </AuthStateContext.Provider>32 );33}3435// 4. Custom Hooks for easier consumption36export const useAuthState = () => useContext(AuthStateContext);37export const useAuthDispatch = () => useContext(AuthDispatchContext);3839// 5. Usage in a component40function UserProfile() {41 const { user, isAuthenticated } = useAuthState();42 const dispatch = useAuthDispatch();4344 if (!isAuthenticated) return <button onClick={() => dispatch({ type: 'LOGIN', payload: { name: 'Dan' } })}>Login</button>;4546 return (47 <div>48 <p>Welcome, {user.name}!</p>49 <button onClick={() => dispatch({ type: 'LOGOUT' })}>Logout</button>50 </div>51 );52}
🏋️ Practice Exercise
- Implement a 'ThemeContext' that toggles between 'light' and 'dark' modes for the whole app.
- Build a 'LanguageSelector' using Context to provide translations (i18n).
- Create a 'Global State' object with nested properties. Use a component to update only one property and observe which other components re-render.
- Refactor a 'Prop Drilling' scenario (3+ levels) using Context.
⚠️ Common Mistakes
Putting everything into a single 'GlobalContext' (leading to unnecessary re-renders).
Using Context for highly frequent updates (like a mouse position or a fast timer).
Forgetting to wrap the app in the Provider, causing
useContextto return undefined.Not splitting state and dispatch contexts, which forces components that only need to dispatch to re-render when state changes.
💼 Interview Questions
🎤 Mock Interview
Practice a live interview for Context API & useReducer