跳到主要内容

useReducer Hook

useReducer = useState for complex state logic


What is useReducer?

"State management with reducer pattern"

useReducer is a React Hook for managing complex state logic using a reducer function.

"useReducer is a React Hook that manages state using a reducer function, similar to Redux, useful for complex state logic."


Basic Syntax

useReducer(reducer, initialState)

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

Returns current state and dispatch function.

"useReducer takes a reducer function and initial state, returning the current state and a dispatch function."


Reducer Function

(state, action) => newState

function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: 0 };
default:
return state;
}
}

"The reducer function takes current state and an action, returning the new state based on the action type."


Dispatch Actions

dispatch with action object

const [state, dispatch] = useReducer(reducer, { count: 0 });

dispatch({ type: "increment" });
dispatch({ type: "decrement" });
dispatch({ type: "reset" });

"Dispatch sends actions to the reducer, which updates state based on the action type."


When to Use useReducer

Complex state · Multiple sub-values · Predictable updates

Use when:

  • Complex state logic
  • State has multiple sub-values
  • Next state depends on previous
  • Need predictable state updates

"Use useReducer for complex state logic, multiple related state values, or when state updates follow predictable patterns."


useReducer vs useState

useReducer = complex, useState = simple

ScenarioHook
Simple stateuseState
Complex logicuseReducer
Multiple valuesuseReducer
Predictable updatesuseReducer

"Use useState for simple state, useReducer for complex state logic or multiple related values."


Lazy Initialization

Function initializer

function init(initialCount) {
return { count: initialCount };
}

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

"useReducer supports lazy initialization with a third parameter function for expensive initial state setup."


Action Payloads

Actions can carry data

function reducer(state, action) {
switch (action.type) {
case "add":
return { items: [...state.items, action.payload] };
case "remove":
return { items: state.items.filter((i) => i.id !== action.payload) };
default:
return state;
}
}

dispatch({ type: "add", payload: newItem });

"Actions can include payload data for more complex state updates."


9️⃣ Common Pattern: Todo List

Classic useReducer example

function todoReducer(state, action) {
switch (action.type) {
case "add":
return [...state, action.payload];
case "toggle":
return state.map((todo) =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo,
);
case "delete":
return state.filter((todo) => todo.id !== action.payload);
default:
return state;
}
}

"Todo lists are a common useReducer pattern, managing arrays of items with add, toggle, and delete actions."


Best Practices

✅ Keep reducers pure (no side effects) ✅ Use action types as constants ✅ Handle all action types ✅ Return state for unknown actions ✅ Use TypeScript for type safety ❌ Don't mutate state directly


"useReducer manages complex state using a reducer function that takes state and action, returning new state. It's useful for complex logic, multiple related values, and predictable updates. Dispatch sends actions to the reducer. Prefer useReducer over useState when state logic is complex or follows predictable patterns."


🧠 Ultra-Short Cheat Sheet

Complex state management
Reducer pattern
(state, action) => newState
dispatch actions
Better than useState for complex logic
Lazy initialization
Action payloads
Pure functions