State Management
Context plus useReducer — used in the Shopping Cart project and formalized in Intermediate Chapters 2–3 — genuinely works for global state, and Chapter 7's useMemo fix solved its biggest re-render problem. It still has real limits at scale: every piece of global state generally needs its own Provider wrapping the app, and even with memoization, splitting state cleanly across many unrelated concerns gets unwieldy. Zustand and Redux Toolkit are the two most common dedicated answers to that — different philosophies, both still built around the same core idea: state living outside any one component, with components subscribing to the pieces they need.
Zustand — Minimal Global State
create() builds a store and a hook for reading it, in one step — the store itself lives entirely outside the React component tree, so there's no <Provider> wrapping anything, unlike every Context example so far. Each call to useCounterStore(selector) subscribes only to the specific piece of state that selector returns — Counter only re-renders when count itself changes, not when some unrelated piece of the same store changes, solving Context's all-or-nothing re-render problem directly rather than needing the useMemo workaround from Chapter 7.
Rebuilding the Shopping Cart with Zustand
The duplicate-entry-check logic from Project 6's addToCart is identical here — Zustand changes where state lives and how components subscribe to it, not the immutable-update rules underneath. Any component anywhere can call useCartStore((s) => s.items) or useCartStore((s) => s.addToCart) directly — no CartProvider wrapping the app, no useContext call.
Redux Toolkit — More Structure, More Ceremony
Redux Toolkit follows the same dispatch/action/reducer shape as useReducer from Intermediate Chapter 3, scaled up with "slices" for organizing many pieces of state, a single combined store, and (unlike a hand-written reducer) the ability to write code that looks like direct mutation inside a reducer safely — Redux Toolkit uses a library called Immer underneath to translate that into a proper immutable update automatically. It does still need a <Provider> wrapping the app, much like Context.
useMemo can't fully solve, or a team that specifically wants Redux's strict structure and devtools ecosystem. If useReducer + Context (with the Chapter 7 useMemo fix) is working fine for an app's actual needs, that's a completely reasonable place to stop — neither Zustand nor Redux Toolkit need to be reached for "just in case."
| Context + useReducer | Zustand | Redux Toolkit | |
|---|---|---|---|
| Needs a Provider? | Yes | No | Yes |
| Selective re-renders? | Manual (useMemo) | Built in | Built in (useSelector) |
| Setup ceremony | Low | Very low | Higher |
| Ecosystem / devtools | None built-in | Small, growing | Large, mature |
| Best fit | Small-to-medium global state | Most apps wanting simplicity | Large teams, strict conventions |
Coding Challenges
Build a Zustand counter store with increment, decrement, and reset actions, and use it from two completely unrelated components, confirming both stay in sync with no Provider anywhere in the app.
📄 View solutionRebuild Project 6's shopping cart logic (items, addToCart with the duplicate-check behavior, removeFromCart) as a Zustand store, and use it from a product list component and a separate cart-display component.
📄 View solutionBuild the same counter from Challenge 1 using Redux Toolkit instead (createSlice, configureStore, a Provider, useSelector, useDispatch), and compare the amount of code each approach needed for identical behavior.
📄 View solutionChapter 1 Quick Reference
- Zustand —
create()builds a store + hook; no Provider; selective subscriptions built in - Redux Toolkit —
createSlice/configureStore; needs aProvider; mature ecosystem/devtools - Both still rely on the same immutable-update rules from Fundamentals Ch 3 underneath (Redux Toolkit just hides it via Immer)
- Neither replaces Context + useReducer by default — reach for them when scale genuinely demands it
- Next chapter: React Query — the same pattern applied specifically to server data, first used informally in Project 7