liveBook · Manning

Reduction operation

As explained in React Quickly, Second Edition

A reducer is a function that calculates a next state from a current state and an action or event.

A reduction operation calculates the next state from the current state and an action. In React, useReducer connects that calculation to a component: dispatch an action describing what happened, and the reducer returns the state to use next. The reducer itself should be pure and free of side effects. section 10.2 section 10.6

Increment or decrement a counter

Start with `const [counter, dispatch] = useReducer(reducer, 0)`. An Increment button calls `dispatch({ type: "INCREMENT" })`; a Decrement button dispatches `"DECREMENT"`. The reducer examines `type` and returns `state + 1` or `state - 1`. Unlike setting a value directly, the button names an action and leaves the calculation to the reducer. section 10.2

Listing 10.5 Counter component with reducer
import { useReducer } from "react";
function reducer(state, { type }) {                       #1
  switch (type) {
    case "INCREMENT":                                     #2
      return state + 1;                                   #2
    case "DECREMENT":                                     #2
      return state - 1;                                   #2
    default:
      return state;
  }
}
function Counter() {
  const [counter, dispatch] = useReducer(reducer, 0);     #3
  return (
    <section>
      <h1>Counter: {counter}</h1>
      <div>
        <button onClick={
          () => dispatch({ type: "INCREMENT" })           #4
        }>
          Increment
        </button>
        <button onClick={
          () => dispatch({ type: "DECREMENT" })           #4
        }>
          Decrement
        </button>
      </div>
    </section>
  );
}
function App() {
  return <Counter />;
}
export default App;

The complete counter shows the reducer, its initial state, and both button dispatches together. section 10.2

The payoff grows when state values depend on one another. A loader needs a status, result, and error; a failure action can update the relevant values together instead of relying on several separate setter calls. Actions can carry a payload, such as an error message or a successful result. Define each transition carefully: a reducer does not prevent invalid combinations unless its returned states do. section 7.1.2 section 10.2.1

Reach for a reducer when state updates need a shared home:

  • Reset a timer by considering both of its state values in one action. section 12.4
  • Manage task and step updates with separate actions; when reprioritizing steps, return a new array rather than mutating the old one. section 13.3 section 13.4

A reducer is a choice, not a requirement: useState can manage the same state. A simple counter is useful for learning the API, but the extra structure earns its place when related updates or many action types become difficult to coordinate. section 7.1.2 section 13.7

How React Quickly, Second Edition covers it

How deep it goes
Works through counter and loader reducers, then extends the pattern through timer and task-manager exercises without requiring it for simple state.
Examples
Uses increment and decrement buttons, a data loader, timer reset, and task-step editing and prioritization.
What it assumes
Builds on React component state and button events while introducing the reducer and dispatch API through a counter.
What you can do after
Build it from scratch with useReducer and dispatch, then apply actions to coordinated UI updates without mutating existing arrays.
How it connects
Connects useReducer and dispatch to useState, interdependent state, immutable array updates, and React Context.

Also explained in

Compare how 9 books explain reduction operation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of React Quickly, Second Edition. The section links point to the parts of the book it draws on.