So far the provider changed the cart with setCart wherever it needed to. With useReducer, every change gets a name. The provider calls dispatch with an action, an object with a type, like { type: "removed", productId: 6 }. One function, the reducer, takes the old state and the action and returns the new state.
A reducer for a counter looks like this:
function countReducer(count, action) {
switch (action.type) {
case "increased":
return count + 1;
case "reset":
return 0;
default:
return count;
}
}
A reducer must never change the old state. For an array, return a new one: [...items, line] adds a line, map swaps one line for a copy, filter drops lines. push would change the old array, and React, which compares the old items with the new ones, would see no change at all.
The check adds a Mug twice and a Teapot, removes the Teapot and places the order. Then it calls your reducer on a frozen cart that can't be changed:
> click "Cart (3)"
item: Mug × 2 $24
item: Teapot × 1 $22
> click "Remove" in "Teapot"
request: DELETE /api/cart/6 -> 200
text: Total: $24
> click "Place order"
link: Cart (0) -> /cart
> cartReducer, called on a frozen cart: Mug × 2
added Pen -> Mug × 2, Pen × 1
quantity_set Mug to 5 -> Mug × 5
removed Mug -> (empty)
cleared -> (empty)
the old cart: Mug × 2
Your task: in src/cartReducer.js, add a case for "added", "quantity_set", "removed" and "cleared" above default, each returning new items.
Assignment
Follow the Coding Tutorial to teach cartReducer the four actions that CartProvider and CheckoutPage dispatch.
Hint
Every case returns a new array: a spread for added, map for quantity_set, filter for removed, and [] for cleared. A case with no return below it falls through to default.
Free plan: 30 tutor messages. PRO is unlimited.
