๐ง State Management
Every piece of state has a cost. A Programmer distinguishes between Global State (shared across the app), Local State (contained in one component), and Server Cache (mirrored data from an API). The best state management strategy is often the one that stores the least amount of data globally.
๐๏ธ 1. Unidirectional Data Flow (Redux, Vuex)
Section titled โ๐๏ธ 1. Unidirectional Data Flow (Redux, Vuex)โThe โStrictโ architecture. Inspired by the Flux pattern, it ensures that state changes are explicit and traceable.
- How it works:
Action โฎ Dispatcher โฎ Store โฎ View. You never mutate state directly; you dispatch an action that a Reducer uses to calculate a new state. - Pros: Predictable, excellent debugging (Time-travel debugging), and easy to test business logic.
- Cons: High boilerplate (โCeremonyโ). You often need many files just to update a single boolean.
๐ 2. Atomic & Modular State (Zustand, Pinia)
Section titled โ๐ 2. Atomic & Modular State (Zustand, Pinia)โThe modern evolution. These libraries strip away the boilerplate while keeping the benefits of a central store.
- Zustand (React): A small, fast, and scalable state management solution using hooks. It doesnโt require a โProviderโ wrapping your app, which avoids unnecessary re-renders.
- Pinia (Vue): The successor to Vuex. It is intuitive, supports Hot Module Replacement, and has native TypeScript support.
- Pros: Extremely low boilerplate, high developer velocity, and easy to split into โstoresโ (e.g.,
useUserStore,useCartStore).
๐ก 3. Signals (Fine-Grained Reactivity)
Section titled โ๐ก 3. Signals (Fine-Grained Reactivity)โThe current โfrontierโ of state management (Solid.js, Preact, Angular, Vue).
- How it works: Instead of a component re-rendering because an object changed, a Signal is a wrapper around a value. When the value changes, the Signal surgically updates only the specific DOM nodes or computations that โsubscribedโ to it.
- Pros: Performance is incredible. It eliminates the โVirtual DOM Diffingโ overhead for state updates.
- Cons: Requires a different mental model (you are dealing with โreferencesโ to values rather than the values themselves).
โ๏ธ Strategic Comparison
Section titled โโ๏ธ Strategic Comparisonโ| Pattern | Examples | Best For | Complexity |
|---|---|---|---|
| Flux / Redux | Redux Toolkit, Vuex | Massive teams, highly complex state transitions. | High |
| Hooks / Stores | Zustand, Pinia | Most modern web apps, rapid development. | Low |
| Atoms | Recoil, Jotai | Apps with complex, cross-dependent state pieces. | Moderate |
| Signals | Svelte, Solid, Angular | Performance-critical apps, high-frequency updates. | Low/Moderate |
๐ ๏ธ Implementation Patterns
Section titled โ๐ ๏ธ Implementation Patternsโ1. The โServer Stateโ vs. โUI Stateโ Split
Section titled โ1. The โServer Stateโ vs. โUI Stateโ SplitโA common Programmer mistake is putting API data in Redux/Zustand.
- Programmerโs Move: Use React Query (TanStack Query) or SWR for server data. These handle caching, revalidation, and loading states automatically. Use your state manager (Zustand/Pinia) only for true UI state (e.g., โIs the sidebar open?โ, โCurrent themeโ).
2. State Normalization
Section titled โ2. State NormalizationโAvoid nested objects in your store. If you have a list of posts, each with an array of comments, itโs hard to update.
- Strategy: Store them like a database:
posts: { [id]: post }andcomments: { [id]: comment }. Use IDs to link them. This makes updates $O(1)$ and prevents data inconsistency.
3. Derived State (Selectors)
Section titled โ3. Derived State (Selectors)โNever store data in the state that can be calculated from other data.
- Example: Donโt store
totalPrice. Store theitemsarray and use a Selector (likereselector a computed property) to calculate the total. This ensures the total is always โin syncโ and avoids โdual source of truthโ bugs.
๐ก Note: Before reaching for a library, ask: โCan I solve this with a simple Prop Drill or the Context API?โ For many apps, the built-in tools are sufficient. Only introduce a state management library when the complexity of passing data between distant components becomes a bottleneck for development.