JAVASCRIPT

Managing Complex State with `useReducer`

Learn to manage complex application state more predictably than `useState` using React's `useReducer` hook, ideal for state transitions and multiple sub-values.

import React, { useReducer } from 'react';

const initialState = { count: 0, loading: false, error: null };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'decrement':
      return { ...state, count: state.count - 1 };
    case 'startLoading':
      return { ...state, loading: true, error: null };
    case 'finishLoading':
      return { ...state, loading: false };
    case 'setError':
      return { ...state, loading: false, error: action.payload };
    default:
      throw new Error();
  }
}

function CounterWithReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <h1>Count: {state.count}</h1>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
      <p>{state.loading && 'Loading...'}</p>
      {state.error && <p style={{ color: 'red' }}>Error: {state.error}</p>}
      <button onClick={() => {
        dispatch({ type: 'startLoading' });
        setTimeout(() => {
          // Simulate an async operation
          const success = Math.random() > 0.5;
          if (success) {
            dispatch({ type: 'finishLoading' });
            alert('Operation successful!');
          } else {
            dispatch({ type: 'setError', payload: 'Failed to complete operation.' });
          }
        }, 1000);
      }}>
        Simulate Async Action
      </button>
    </div>
  );
}

export default CounterWithReducer;
How it works: The `useReducer` hook is an alternative to `useState` for managing more complex state logic. It takes a reducer function and an initial state, returning the current state and a `dispatch` function. The reducer function takes the current state and an action, returning the new state based on the action type. This pattern centralizes state updates, making them more predictable and testable, especially when state transitions depend on multiple values or follow complex logic.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs