React useReducer for Complex State — Forms, State Machines, and Redux Patterns

Master useReducer for complex state management in React. Covers form state, state machines, combining with useContext for global state, and when to choose useReducer over useState.

State Hooks

Detailed Explanation

Complex State with useReducer

useReducer is an alternative to useState that excels at managing complex, interdependent state transitions.

When to Choose useReducer

  • State has multiple sub-values that update together
  • Next state depends on previous state
  • You want to centralize and test state logic
  • You need to pass dispatch (stable reference) to deep children

Form State Example

interface FormState {
  name: string;
  email: string;
  errors: Record<string, string>;
  submitting: boolean;
}

type FormAction =
  | { type: "SET_FIELD"; field: string; value: string }
  | { type: "SET_ERRORS"; errors: Record<string, string> }
  | { type: "SUBMIT_START" }
  | { type: "SUBMIT_SUCCESS" }
  | { type: "RESET" };

function formReducer(state: FormState, action: FormAction): FormState {
  switch (action.type) {
    case "SET_FIELD":
      return { ...state, [action.field]: action.value, errors: {} };
    case "SET_ERRORS":
      return { ...state, errors: action.errors, submitting: false };
    case "SUBMIT_START":
      return { ...state, submitting: true, errors: {} };
    case "SUBMIT_SUCCESS":
      return { name: "", email: "", errors: {}, submitting: false };
    case "RESET":
      return { name: "", email: "", errors: {}, submitting: false };
  }
}

State Machine Pattern

useReducer naturally maps to state machines, making impossible states impossible:

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: User[] }
  | { status: "error"; error: string };

Mini Redux with useReducer + useContext

Combine useReducer with useContext to create a global state container without external libraries. Pass the dispatch function through context -- it has a stable identity and does not cause unnecessary re-renders.

Use Case

Use useReducer for multi-step forms, shopping carts, data fetching state machines, and any scenario where you want centralized, testable state transitions.

Try It — React Hooks Reference

Open full tool