JAVASCRIPT
Global State Management with `useContext` and `useReducer`
Implement powerful global state management in React using `useContext` and `useReducer` to avoid prop drilling and maintain centralized, predictable state updates.
import React, { createContext, useReducer, useContext } from 'react';
// 1. Define initial state and reducer
const initialState = {
user: { name: 'Guest', isAuthenticated: false },
theme: 'light',
};
function appReducer(state, action) {
switch (action.type) {
case 'LOGIN':
return { ...state, user: { name: action.payload.name, isAuthenticated: true } };
case 'LOGOUT':
return { ...state, user: { name: 'Guest', isAuthenticated: false } };
case 'TOGGLE_THEME':
return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' };
default:
return state;
}
}
// 2. Create a Context
const AppContext = createContext();
// 3. Create a Provider component
export function AppProvider({ children }) {
const [state, dispatch] = useReducer(appReducer, initialState);
return (
<AppContext.Provider value={{ state, dispatch }}>
{children}
</AppContext.Provider>
);
}
// 4. Create a custom hook to consume the context easily
export function useAppContext() {
return useContext(AppContext);
}
// Example Usage:
function UserInfo() {
const { state, dispatch } = useAppContext();
const { user } = state;
return (
<div>
<p>Welcome, {user.name}!</p>
{user.isAuthenticated ? (
<button onClick={() => dispatch({ type: 'LOGOUT' })}>Logout</button>
) : (
<button onClick={() => dispatch({ type: 'LOGIN', payload: { name: 'Alice' } })}>Login</button>
)}
</div>
);
}
function ThemeSwitcher() {
const { state, dispatch } = useAppContext();
const { theme } = state;
return (
<div style={{ background: theme === 'dark' ? '#333' : '#eee', color: theme === 'dark' ? '#eee' : '#333', padding: '10px' }}>
<p>Current Theme: {theme}</p>
<button onClick={() => dispatch({ type: 'TOGGLE_THEME' })}>Toggle Theme</button>
</div>
);
}
// Root App Component (to demonstrate)
function App() {
return (
<AppProvider>
<div>
<h1>My React App</h1>
<UserInfo />
<ThemeSwitcher />
</div>
</AppProvider>
);
}
export default App;
How it works: This pattern leverages `useContext` and `useReducer` for efficient global state management, eliminating prop drilling. The `AppProvider` wraps your application, providing the global `state` and `dispatch` function to any child component via `AppContext`. The custom `useAppContext` hook simplifies consuming this context, allowing components to access and update shared state without explicit prop passing, leading to cleaner and more maintainable code.