Trovella Wiki

State Management

How client state, server state, URL state, and form state are managed across the Trovella web application.

Trovella uses a layered state management approach. Each layer has a dedicated tool chosen for its specific strengths, and the boundaries between layers are deliberate.

The State Layers

LayerToolStatusPurpose
Server stateTanStack Query v5 via tRPC React QueryActiveCache, fetch, and synchronize server data
Client stateReact useState / useCallback / useMemoActiveComponent-local and feature-scoped UI state
Client state (global)ZustandPlannedCross-component client state (not yet needed)
URL statenuqsPlannedShareable/bookmarkable UI state in query params
Form stateControlled inputs + Zod schemasActiveForm field values and validation
Form state (complex)React Hook FormPlannedMulti-step forms with complex validation

The "planned" tools are accepted in the tech stack (see ADR-005: Framework Decision) but have not been installed yet because the existing patterns are sufficient for current features. They will be added when explicit complexity triggers are hit.

Current Architecture

Browser
  |
  +-- TanStack Query cache (server state)
  |     Managed by tRPC React Query hooks
  |     30s stale time, automatic refetch
  |
  +-- React useState (client state)
  |     Component-local: pagination, filters, selections
  |     Feature-scoped: AI playground settings, stream state
  |
  +-- Controlled inputs (form state)
        Direct useState + onChange handlers
        Zod schemas from @repo/validators for server-side validation

Decision Criteria for Choosing a Layer

Use tRPC/TanStack Query when the data comes from the server. This is the most common case -- admin dashboards, research plans, settings, and all CRUD operations go through tRPC queries and mutations.

Use React useState for UI-only state that does not need to survive a page navigation: pagination offsets, expanded/collapsed rows, selected items, filter values, loading indicators.

Use Zustand (when added) for client state that must be shared across unrelated component subtrees without prop drilling. No current feature requires this.

Use nuqs (when added) for state that should be reflected in the URL so users can bookmark or share a specific view -- filter combinations, search queries, active tabs.

Use React Hook Form (when added) for forms with many fields, cross-field validation, or multi-step wizards. Current forms are simple enough that controlled inputs work well.

Pages in This Topic

PageWhat It Covers
Server StatetRPC React Query hooks, query patterns, cache invalidation, the provider tree
Client StateReact useState patterns, custom hooks, and the path to Zustand
Form HandlingControlled inputs, Zod validator schemas, and the path to React Hook Form

On this page