Capítulo 28 de 116

Chapter 28: Choosing the State Structure

Core Idea

Five principles for structuring state well: group related fields that always change together, avoid contradictions between separate state variables, avoid redundant state that duplicates something derivable at render time, avoid duplicating the same data in two places, and avoid deeply nested state that's painful to update immutably.

Key Concepts

  • Group related state: if two state variables always update together (e.g. x/y cursor coordinates), merge them into one object — reduces the chance of forgetting to update one, and simplifies the mental model. Don't over-apply this though: only merge fields that are genuinely always in sync.
  • Avoid contradictions in state: isSending and isSent as two independent booleans allow the impossible combination isSending: true, isSent: true — replace with a single status variable that can only hold one value at a time (the same technique from Ch 27).
  • Avoid redundant state: if a value can be calculated from existing props/state during render, don't also store it as its own state variable — a fullName state kept "in sync" with firstName/lastName via effects is a classic anti-pattern; just compute firstName + ' ' + lastName inline at render time instead.
  • Avoid duplication in state: storing both a full list and a "selected item" copy (rather than a selected item's id/index) means every edit has to be manually kept in sync across both places, and can drift. Store an identifier or index, and derive the actual selected object from the source list at render time.
  • Avoid deeply nested state: deeply nested objects/arrays make immutable updates (Ch 25/26) increasingly painful — each nesting level needs its own spread. Prefer flattening data (e.g. a normalized { id: item } map plus arrays of ids) when updates start requiring many nested spreads.

Code Examples

// Redundant: fullName as its own state, easy to desync
const [firstName, setFirstName] = useState('Ada');
const [lastName, setLastName] = useState('Lovelace');
// ✅ derive instead of storing
const fullName = firstName + ' ' + lastName;
  • What it demonstrates: eliminating redundant state by deriving a value at render time instead of tracking it as a separate useState.

Key Takeaways

  1. Before adding a new useState, ask: can this be computed from state/props I already have? If yes, don't store it.
  2. Store IDs/indices for "which item is selected," not a duplicated copy of the item itself — derive the actual object from the canonical list.
  3. When update logic needs three or more nested spreads to reach the field you're changing, that's a signal to flatten the state shape, not a signal to reach for a bigger spread.

Connects To

  • Ch 27 (Reacting to Input with State): the contradiction-avoidance principle applied there to visual-state modeling.
  • Ch 25 (Updating Objects in State): why deep nesting specifically makes immutable updates harder.
  • Ch 31 (Extracting State Logic into a Reducer): a structural alternative when state transitions get complex regardless of shape.