Introduction

The useReducer hook lets you use a reducer in your component

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

What’s this dispatch function?

The dispatch function specifies how the state gets updated. It must be a pure function and should take an action with a portion of the state to update.

useReducer returns an array containing the current state and a dispatch function:

import { useReducer } from "react";

//Note: state comes first then action in that order
function reducer(state, action) {
  if (action.type === "increment_age") {
    return {
      age: state.age++,
      name: state.name
    };
  }
}

function MyComponent() {
  const [state, dispatch] = useReducer(reducer, { age: 29, name: "Naftali" });

  const handleClick = () => {
    dispatch({ type: "increment_age" });
  };

  return (
    <>
      <button onClick={handleClick}>Update Age</button>
      <p>New age {state.age}</p>
      <p>Name: {state.name}</p>
    </>
  );
}

export default function App() {
  return (
    <>
      <MyComponent />
    </>
  );
}

A complete example can be found here

Caveats

The state is immutable, any changes to the state will cause an error to be thrown. For objects and arrays, we return a copy of the state plus the newly updated portion of the state, for example in code:

For an array, our reducer becomes:

function reducer(state, action) {
  if (action.type === "update_cart") {
    return {
      // copy over all state properties
      ...state,
      // state is imutable so we return a copy of items plus our inserted item
      items: [...state.items, action.item]
    };
  }
}

In the above reducer, we copy over the state object using the spread operator and update the items by copying the initial items [...state.items, action.item].

Doing state.items.push() fails as we are mutating the state, push method updates and changes(mutates) the underlying array


Found this article helpful? You may follow me on Twitter where I tweet about interesting topics on software development.