guanghu/docs/adr/0026-props-down-no-global-state.md
冰朔 8739805f99
Some checks failed
Auto-update PR branches / Update open PR branches (push) Has been cancelled
CI / Frontend Static Quality Checks (push) Has been cancelled
CI / Frontend Tests & Coverage (push) Has been cancelled
CI / Rust Tests & Quality Checks (push) Has been cancelled
CI / Linux build verification (push) Has been cancelled
Release (Alpha) / Compute alpha version (push) Has been cancelled
Release (Alpha) / Build release artifacts (push) Has been cancelled
Release (Alpha) / GitHub Release (alpha) (push) Has been cancelled
Release (Alpha) / Update docs and release pages (push) Has been cancelled
Deploy docs / Build VitePress site (push) Has been cancelled
Deploy docs / Deploy to GitHub Pages (push) Has been cancelled
光湖开源源码快照 · Tolaria AGPL 分叉基线 · 独立更新链
2026-07-05 17:45:16 +08:00

2.0 KiB

type, id, title, status, date, superseded_by
type id title status date superseded_by
ADR 0026 Props-down callbacks-up (no global state management) superseded 2026-02-15 0115

Context

React apps commonly adopt global state management libraries (Redux, Zustand, Jotai, Context) to share state across components. For Laputa, the component tree is relatively shallow (App → panels → sub-components), and the data flow is predictable. Adding a state management library would increase complexity without proportional benefit.

Decision

No global state management (no Redux, no Context for data). App.tsx owns the state and passes it down as props. Child-to-parent communication uses callback props (onSelectNote, onCloseTab, etc.). Local state uses useState/useReducer.

Options considered

  • Option A (chosen): Props-down, callbacks-up — simple, predictable data flow, easy to trace state changes, no library dependency. Downside: prop drilling through deep trees, verbose parent components.
  • Option B: Redux/Zustand global store — centralized state, easy cross-component access. Downside: boilerplate, indirection, harder to trace state changes, over-engineering for a single-window app.
  • Option C: React Context for shared state — built-in, no library. Downside: re-renders on any context value change, performance issues with large state objects.

Consequences

  • App.tsx is the state orchestrator — it holds vault entries, active note, sidebar selection, and all top-level state.
  • Components receive data and callbacks as props — no useContext for data access.
  • Hooks (useVaultLoader, useNoteActions, useTabManagement, etc.) encapsulate state logic but return values consumed by App.tsx.
  • Prop drilling is mitigated by composing hooks and keeping the component tree shallow.
  • Components are easy to test in isolation (just pass props).
  • Re-evaluation trigger: if the component tree deepens significantly or cross-cutting state becomes unmanageable with props.