Developer Cheatsheets
Patterns Worth Knowing
State Management Using Immer with Context API

How to enhance state management with Immer

Immer is a powerful library that simplifies immutable updates. Immer uses the concept of mutable drafts to make immutable updates straightforward.

Immer provides a helper function called produce, which takes in your current state and a function where you can write code that mutates the state. It then returns a new state based on the mutations you made. This means we don't have to write complex code using the spread operator or Object.assign() to make immutable updates.

Let's revise our cartReducer from our previous shopping cart case study to use Immer.

Step 1: Setting Up with Immer

First, we need to install Immer and import the produce function:

npm install immer
import produce from "immer";

Step 2: Updating the Reducer

With Immer, our reducer now looks like this:

const cartReducer = produce((draft, action) => {
  switch (action.type) {
    case "ADD_ITEM":
      draft.push(action.item);
      break;
    case "REMOVE_ITEM":
      const index = draft.findIndex((item) => item.id === action.itemId);
      if (index !== -1) {
        draft.splice(index, 1);
      }
      break;
    case "UPDATE_QUANTITY":
      const item = draft.find((item) => item.id === action.itemId);
      if (item) {
        item.quantity = action.quantity;
      }
      break;
    case "RESET_CART":
      return [];
    default:
      return;
  }
});

With produce, we just modify the draft directly. produce automatically generates a new state based on our changes.

Step 3: Using the Reducer

The usage of our reducer with useReducer stays the same:

const [items, dispatch] = useReducer(cartReducer, []);

We can still call dispatch with an action object:

dispatch({ type: "ADD_ITEM", item: newItem });

Note: While produce simplifies our reducer code, remember that Immer can have performance implications for very large states or complex mutations. It's a powerful tool, but it's not always necessary, especially for simpler states. As always, use the right tool for the job, and keep slaying that code!

By combining React's useReducer and useContext with Immer, we're now able to manage complex state more easily and with less code, while still preserving immutability. This combo can be a serious game-changer for your state management strategy! Happy coding!