vroqjs.com

07-debuggable-state/04-state-shape.md

State shape

State shape

The shape of the application state should be easy to inspect, predictable, and aligned with feature ownership.

A well-designed state shape helps both humans and LLMs quickly understand how the system behaves.

Principles

Good state shape should:

  • reflect feature boundaries
  • avoid deep or confusing nesting
  • group related values together
  • make debugging easy

Prefer feature slices

State should usually be grouped by feature.

Example:

{
  files: {
    items: []
  },

  editor: {
    content: ""
  },

  ui: {
    modal: null
  }
}

This makes it easy to see which reducer owns which slice.

Avoid deeply nested structures

Deeply nested state trees are harder to update and reason about.

Prefer flatter structures unless nesting clearly reflects domain relationships.

Keep state explicit

Avoid storing derived data that can easily be recomputed.

Instead store the minimal source-of-truth values.

Reusing the same feature multiple times

Sometimes the same feature must appear multiple times in one app (for example multiple counters, editors, or forms).

In this case the feature state should usually be keyed by an identifier.

Example:

{
  counters: {
    counterA: { value: 0 },
    counterB: { value: 10 }
  }
}

Reducers then update the specific instance using the id from the action payload.

Example:

case "COUNTER_INCREMENT":
  const id = action.payload.id;

  return {
    ...root,
    counters: {
      ...root.counters,
      [id]: {
        ...(root.counters[id] || { value: 0 }),
        value: (root.counters[id]?.value || 0) + 1
      }
    }
  };

UI sections then pass the id when dispatching actions.

Example:

incrementCounter("counterA")
incrementCounter("counterB")

This pattern allows the same feature UI to be reused multiple times without duplicating reducers or state structures.

Final rule

A reader should be able to inspect initialState.js and quickly understand the main structure of the app's state and how each feature slice is organized.