Prompt
Create a shopping cart using React Context. Requirements:
- CartContext with addItem, removeItem, updateQuantity, clearCart
- Each item has id, name, price, quantity
- Display cart total (price * quantity summed)
- +/- quantity controls that can remove item if qty reaches 0
Solution
A cart is the textbook case for Context: it's read from the catalog, the cart screen, and the checkout badge — prop-drilling it three navigator levels deep is the alternative, and that's worse. The shipping concern here is the module boundary: consumers get useCart() and a fixed API (addItem, removeItem, updateQuantity, clearCart); they never see setItems. Every invariant lives inside the provider.
Mechanics worth naming:
- addItem is an upsert: find the existing line, increment its quantity with map-and-spread; otherwise append with
quantity: 1. Duplicate line-items for the same product is the bug this prevents. - updateQuantity maps to
nullthenfilter(Boolean)— one pass that both updates and evicts when quantity hits zero, without mutating. - The guard hook:
useCartthrows when called outside the provider.createContext(null)plus that throw turns a silentundefined is not a functionthree components later into an immediate, named failure. totalis derived from items withreduce, never stored.
Trade-off to volunteer: value is a fresh object every provider render, so all consumers re-render on any cart change. Correct first; when a consumer gets expensive, wrap value in useMemo and, at scale, split state and actions into two contexts.
Red flag: putting setItems itself in the context value. The moment consumers can write raw state, the upsert and the qty-zero eviction stop being guarantees.
Say it: "The provider owns the invariants and exposes verbs, not setters — and useCart throws outside the provider so misuse fails loudly at the source."