useReducer Hook Demo

What is useReducer?

useReducer is a React Hook that provides an alternative to useState. It's particularly useful for managing complex state logic that involves multiple sub-values or when the next state depends on the previous one.

Basic Syntax:

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

// Reducer function signature
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();
  }
}

// Usage
dispatch({ type: 'increment' });
dispatch({ type: 'decrement' });

Counter with useReducer

Count: 0

Actions performed: 1

Action History:

1. Initial state: 0

✅ This example shows how useReducer manages complex state with action history tracking

Form Handling with useReducer

✅ This example shows complex form state management with validation using useReducer

useState vs useReducer

useState

  • ✅ Simple state updates
  • ✅ Independent state variables
  • ✅ Less boilerplate code
  • ✅ Good for basic state management
  • ❌ Complex state logic becomes messy
  • ❌ Multiple related state updates

useReducer

  • ✅ Complex state logic
  • ✅ Related state updates
  • ✅ Predictable state transitions
  • ✅ Better for testing
  • ❌ More boilerplate code
  • ❌ Overkill for simple state

When to use useReducer:

  • • State has multiple sub-values
  • • Next state depends on previous state
  • • Complex state logic
  • • State transitions need to be predictable
  • • Multiple components need same state logic
  • • State updates involve multiple actions

Best Practices & Common Gotchas

✅ Best Practices

  • • Always return new state objects (don't mutate)
  • • Use TypeScript for type safety
  • • Keep reducer functions pure (no side effects)
  • • Use switch statements for action types
  • • Throw errors for unknown actions
  • • Use action creators for complex payloads

❌ Common Gotchas

  • • Mutating state directly instead of returning new object
  • • Forgetting to handle all action types
  • • Making reducer functions impure (side effects)
  • • Using useReducer for simple state (overkill)
  • • Not using TypeScript (loses type safety)
  • • Putting too much logic in components instead of reducer

💡 Pro Tips

  • • Combine with useContext for global state management
  • • Use useCallback for dispatch functions passed to children
  • • Test reducer functions separately from components
  • • Consider using immer for complex state updates
  • • Create action creators for better maintainability
  • • Use lazy initialization for expensive initial state