Web Development

State Management

Every non-trivial web application eventually hits the same wall: component-local state is no longer enough. A shopping cart that must be visible in the header, the sidebar, and the checkout page cannot live in any single component. State management libraries are the architecturally correct answer - and the wrong choice here compounds as the codebase grows.

  • **Airbnb** runs a Redux store at the root of its search page that tracks filters, map bounds, hovered listing ID, and pagination simultaneously. Fine-grained selectors ensure the map component does not re-render when pagination changes.
  • **Figma's** multiplayer editor uses a signal-inspired reactive system to propagate canvas changes. A single user move updates only the ~50 DOM nodes representing the moved object, not a full re-render of a canvas with thousands of elements.
  • **Linear** (project management SaaS) switched from Redux to Zustand in 2021, cutting bundle size by 8 KB and reducing boilerplate by roughly 40% across 60+ store slices, as documented in their engineering blog.

Redux

**Redux** introduced a model that seemed absurdly strict in 2015: all application state lives in one immutable JavaScript object. Change it only by dispatching action objects through a pure reducer function. No direct mutation, ever. The pitch was debuggability - if every state transition is a recorded action, the entire application history can be replayed, and Redux DevTools can time-travel to any past snapshot. Twitter, Instagram, and The New York Times adopted it in 2015-2017 when React applications first scaled to hundreds of thousands of lines.

Redux Toolkit (RTK) eliminated most of the 2015 boilerplate: `createSlice` generates action creators automatically, Immer handles immutable updates behind the scenes. RTK Query adds data fetching and caching. The underlying philosophy - single store, pure reducers, actions as the only mutation path - remains unchanged.

What is the core architectural constraint in Redux?

Zustand

**Zustand** (German: "state") emerged as the minimalist reaction to Redux's ceremony. Created by the Poimandres open-source collective, it shipped in 2019 with a single function API. No actions, no reducers, no provider wrapping - just a store hook that components call directly.

Zustand's subscription model is fine-grained by default: a component that selects `s => s.items.length` only re-renders when `items.length` changes, not when unrelated store fields change. This is the opposite of naive React Context, which re-renders every consumer on any context value change. In 2023, Zustand surpassed Redux in weekly npm downloads for new React projects - a shift reflecting the industry's move toward smaller, more ergonomic libraries.

How does Zustand's subscription model differ from React Context?

Pinia

**Pinia** is the official state management library for Vue 3, replacing Vuex in 2022. It integrates with Vue's reactivity system natively. The API mirrors Vue Composition API: stores are defined with `defineStore`, state as reactive refs, and actions as plain async functions. No mutations, no namespaced modules, no boilerplate that Vuex imposed.

Pinia has first-class Nuxt.js integration and automatic SSR hydration support. Vue DevTools displays every Pinia store alongside component state, and time-travel debugging works for Pinia actions. HMR updates stores without losing current state.

Why did Pinia replace Vuex as Vue's recommended state management solution?

Signals

**Signals** are the newest primitive in the state management landscape. SolidJS popularized them in 2021; Angular added them in v16 (2023); Preact, Qwik, and an experimental React proposal all converge on the same idea. A signal is a reactive container: reading it creates a dependency, writing it propagates updates only to code that actually read it. No Virtual DOM diffing, no component re-renders for unaffected nodes.

The fundamental advantage of signals over useState is granularity. In React, calling `setCount` re-runs the entire component function. With signals, only the DOM nodes that actually read the signal update. Benchmarks show SolidJS consistently outperforms React on update-heavy UIs because no Virtual DOM reconciliation is needed: signals know their subscribers precisely.

TC39 has a Signals proposal (Stage 1 as of 2024) co-authored by engineers from Angular, Preact, Solid, Ember, and Vue. If standardized, signals would become a native JavaScript primitive - the same path Promises took from jQuery `$.Deferred` to native `Promise`.

Redux is outdated and should be replaced by Zustand or Signals in all new projects

Each solution occupies a different point on the complexity-vs-ceremony spectrum; large enterprise teams with strict auditing requirements often still choose Redux for its predictable action log and DevTools

Redux's time-travel debugger, action logging, and strict reducer constraints are genuinely valuable when tracking down state bugs across hundreds of components over months. The ceremony that feels excessive in a small app becomes the paper trail that saves a large one.

What makes signals more granular than React's useState?

Key Ideas

  • **Redux:** single immutable store, pure reducers, actions as the only mutation path - maximum predictability and debuggability; Redux Toolkit eliminated most 2015-era boilerplate
  • **Zustand:** minimal API, fine-grained subscriptions via selector functions, no Provider required - surpassed Redux in new-project adoption in 2023
  • **Pinia:** Vue 3's official store, native Composition API integration, no mutations concept - simpler than Vuex while retaining DevTools time-travel
  • **Signals:** the most granular primitive - individual DOM expressions subscribe to reactive containers, no Virtual DOM diffing; adopted by Angular 16, Preact, Solid, Qwik

Related Topics

State management is the connective tissue between UI components and data:

  • React: Fundamentals — useState and useContext are the component-level primitives that state libraries build on top of
  • Vue and Angular: A Comparison — Pinia (Vue) and NgRx/Signals (Angular) are framework-specific takes on the same cross-component state problem
  • Testing: Jest, Playwright — Redux's pure reducers are straightforwardly unit-testable; Zustand stores can be tested with a mock store reset between tests

Вопросы для размышления

  • Redux's action log means every state change is auditable and replayable. Zustand's direct mutation is simpler but loses that audit trail. For which categories of applications is the audit trail worth the ceremony?
  • Signals update individual DOM expressions rather than re-running component functions. Does this make components as a unit of organization less important?
  • Server state (data fetched from an API) and client state (UI flags, selected items) have different lifetimes and invalidation rules. Should they live in the same store, or be managed by separate tools like React Query alongside Zustand?

Связанные уроки

  • comp-01-intro
State Management

0

1

Sign In