Blog>
Snippets

useReducer with Context API

Use useReducer in conjunction with React's Context API to manage and distribute complex application state across multiple components.
// State management using useReducer with Context API

// Reducer function to handle state changes based on action type
const initialState = { count: 0 };
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

// Create context
const CountContext = React.createContext();

// Context Provider component using useReducer hook
function CountProvider({ children }) {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  return (
    <CountContext.Provider value={{ state, dispatch }}>
      {children}
    </CountContext.Provider>
  );
}

// Custom hook to use the context
function useCount() {
  const context = React.useContext(CountContext);
  if (!context) {
    throw new Error('useCount must be used within a CountProvider');
  }
  return context;
}
The code represents a simple counter application state managed with useReducer and the React Context API. It includes an initial state, a reducer function to manage state changes, a context for passing down state, a provider component which encapsulates the useReducer hook, and a custom hook to consume the context in child components.
// Component that displays the count
function CountDisplay() {
  const { state } = useCount();

  return <div>{state.count}</div>;
}
This piece of code provides a CountDisplay component, which uses the custom hook useCount to access the count state and then renders it.
// Component that provides buttons to increment or decrement the count
function CounterControls() {
  const { dispatch } = useCount();

  return (
    <div>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}
This code snippet shows a CounterControls component, which uses the custom hook useCount to dispatch actions for incrementing or decrementing the count state.
// App component that uses CountProvider to wrap the components that need access to the count state
function App() {
  return (
    <CountProvider>
      <CountDisplay />
      <CounterControls />
    </CountProvider>
  );
}
This is the App component which uses the CountProvider to wrap other components such as CountDisplay and CounterControls, enabling them to access the context state and dispatch actions.