Choose the Right React State Strategy
Classify a value before choosing a library. Give each value one clear owner and one source of truth; do not treat all state as global state.
Preferred Mapping
Local UI state -> useState / useReducer
Simple shared dependency -> Context
Shared client state -> Zustand, or Redux Toolkit when architecture warrants it
Server state -> TanStack Query / RTK Query / framework data APIs
URL state -> router and search params
Form state -> native React / form library
Persistent state -> localStorage or IndexedDB behind an appropriate abstraction
These are defaults, not reasons to replace a project's established, suitable architecture.
Classify Ownership and Lifecycle
Ask who owns the value:
- Backend-owned records, search results, products, users, orders, and remote notifications are server state. They require caching, loading and error handling, invalidation, refetching, deduplication, mutations, and staleness management.
- Interaction state owned by the application, such as an open panel, selected tab, browser-only cart, editor draft, or workflow step, is client state.
- Shareable or navigational values such as filters, search terms, pagination, sorting, tabs, categories, and resource IDs usually belong in the URL.
- Inputs, validation, touched state, field arrays, and submission flow belong to the form.
- Persistence is a storage concern, not evidence that state must be global.
Hybrid boundaries are legitimate. For example, backend data may be copied once into independent editable draft state when a user opens an editor. Make that ownership transition explicit.
Escalate Client State Gradually
Prefer this order:
derive it -> keep it local -> lift it to the nearest common parent
-> feature Context -> dedicated client store
- Use
useState for state owned by one component or a small subtree.
- Lift state to the closest common parent when nearby siblings share it.
- Use
useReducer when local transitions become complex, coordinated, previous-state-heavy, or benefit from explicit actions. Multiple object properties alone do not justify a reducer.
- Use Context primarily to distribute simple, infrequently changing dependencies such as theme, locale, authentication session, configuration, dependency instances, or current workspace.
- Avoid a broad Context for frequently updated counters, large editable collections, drag-and-drop, editor, or dashboard state because every Context update makes consumers reconsider rendering.
- Use Zustand for frequently changing client state shared by distant components when Context becomes cumbersome or selectors and domain actions are useful.
- Use Redux Toolkit when a large application or team benefits from strict conventions, middleware, action history, advanced tooling, or complex cross-feature coordination. Prefer RTK Query when Redux Toolkit is already the main architecture.
Respect an existing Redux, Zustand, query, router, or form architecture when it fits the state category. Do not introduce another library without a concrete benefit.
Keep State Minimal and Focused
- Derive values that can be calculated from existing props or state instead of storing them.
- Prefer domain actions such as
addItem, removeItem, and clearCart over exposing unrestricted setters from global stores.
- Split client stores by domain rather than creating one store containing unrelated users, carts, editors, notifications, products, modals, and forms.
- Use narrow selectors; do not subscribe a component to an entire Zustand or Redux store when it needs one value.
- Do not globalize form state unless it must genuinely survive navigation or be shared outside the form.
Keep Server State in a Server Cache
Use TanStack Query for remote lifecycle management unless the framework or established architecture provides the appropriate equivalent. Think of it as a server cache, not a client global store.
Do not copy query results into Zustand, Redux client slices, or component state by default. That creates multiple sources of truth and often requires effects to synchronize them. Copy only at an intentional boundary where the value becomes independently owned client state.
Do not manually rebuild loading flags, cache logic, retries, deduplication, background refresh, invalidation, and mutation state in a client store without a specific architectural reason.
Keep URL State in the URL
Read URL-owned values directly through router APIs. Avoid mirroring search parameters into local state with an effect unless there is an explicit, justified synchronization boundary. URL state should remain shareable, bookmarkable, refresh-safe, and compatible with browser navigation.
Handle Forms Separately
Use native React state and framework form APIs for simple forms. Consider React Hook Form, Formik, or the project's established form abstraction for large or nested forms, dynamic arrays, field-level validation, performance constraints, or complex submission flows.
Review Checklist
For each state value, verify:
- Does it need to be state, or can it be derived?
- Who owns it: backend, URL, form, persistent storage, or the React application?
- Can it stay local or be lifted to a nearby parent?
- Is Context merely distributing a dependency, or being used as a high-frequency global store?
- Is a client store actually necessary, and are consumers using narrow selectors?
- Is backend data incorrectly duplicated outside its server-state cache?
- Are there multiple sources of truth or effects synchronizing state systems?
- Is one enormous global store mixing unrelated domains?
- Does persistence work through a clear abstraction without forcing global scope?
- Does the choice align with the project's existing architecture?
Choose the smallest tool that correctly models the state. The goal is not one state library or the fewest libraries; it is clear ownership and a single source of truth for every category.
1---2name: choose-react-state-management3description: Choose and review React state-management strategies by classifying local UI, shared client, server, URL, form, and persistent state. Apply when designing state architecture, selecting between React state, Context, Zustand, Redux Toolkit, query libraries, routers, or form libraries, or detecting duplicated and over-globalized state.4---56# Choose the Right React State Strategy78Classify a value before choosing a library. Give each value one clear owner and one source of truth; do not treat all state as global state.910## Preferred Mapping1112```text13Local UI state -> useState / useReducer14Simple shared dependency -> Context15Shared client state -> Zustand, or Redux Toolkit when architecture warrants it16Server state -> TanStack Query / RTK Query / framework data APIs17URL state -> router and search params18Form state -> native React / form library19Persistent state -> localStorage or IndexedDB behind an appropriate abstraction20```2122These are defaults, not reasons to replace a project's established, suitable architecture.2324## Classify Ownership and Lifecycle2526Ask who owns the value:2728- Backend-owned records, search results, products, users, orders, and remote notifications are server state. They require caching, loading and error handling, invalidation, refetching, deduplication, mutations, and staleness management.29- Interaction state owned by the application, such as an open panel, selected tab, browser-only cart, editor draft, or workflow step, is client state.30- Shareable or navigational values such as filters, search terms, pagination, sorting, tabs, categories, and resource IDs usually belong in the URL.31- Inputs, validation, touched state, field arrays, and submission flow belong to the form.32- Persistence is a storage concern, not evidence that state must be global.3334Hybrid boundaries are legitimate. For example, backend data may be copied once into independent editable draft state when a user opens an editor. Make that ownership transition explicit.3536## Escalate Client State Gradually3738Prefer this order:3940```text41derive it -> keep it local -> lift it to the nearest common parent42 -> feature Context -> dedicated client store43```4445- Use `useState` for state owned by one component or a small subtree.46- Lift state to the closest common parent when nearby siblings share it.47- Use `useReducer` when local transitions become complex, coordinated, previous-state-heavy, or benefit from explicit actions. Multiple object properties alone do not justify a reducer.48- Use Context primarily to distribute simple, infrequently changing dependencies such as theme, locale, authentication session, configuration, dependency instances, or current workspace.49- Avoid a broad Context for frequently updated counters, large editable collections, drag-and-drop, editor, or dashboard state because every Context update makes consumers reconsider rendering.50- Use Zustand for frequently changing client state shared by distant components when Context becomes cumbersome or selectors and domain actions are useful.51- Use Redux Toolkit when a large application or team benefits from strict conventions, middleware, action history, advanced tooling, or complex cross-feature coordination. Prefer RTK Query when Redux Toolkit is already the main architecture.5253Respect an existing Redux, Zustand, query, router, or form architecture when it fits the state category. Do not introduce another library without a concrete benefit.5455## Keep State Minimal and Focused5657- Derive values that can be calculated from existing props or state instead of storing them.58- Prefer domain actions such as `addItem`, `removeItem`, and `clearCart` over exposing unrestricted setters from global stores.59- Split client stores by domain rather than creating one store containing unrelated users, carts, editors, notifications, products, modals, and forms.60- Use narrow selectors; do not subscribe a component to an entire Zustand or Redux store when it needs one value.61- Do not globalize form state unless it must genuinely survive navigation or be shared outside the form.6263## Keep Server State in a Server Cache6465Use TanStack Query for remote lifecycle management unless the framework or established architecture provides the appropriate equivalent. Think of it as a server cache, not a client global store.6667Do not copy query results into Zustand, Redux client slices, or component state by default. That creates multiple sources of truth and often requires effects to synchronize them. Copy only at an intentional boundary where the value becomes independently owned client state.6869Do not manually rebuild loading flags, cache logic, retries, deduplication, background refresh, invalidation, and mutation state in a client store without a specific architectural reason.7071## Keep URL State in the URL7273Read URL-owned values directly through router APIs. Avoid mirroring search parameters into local state with an effect unless there is an explicit, justified synchronization boundary. URL state should remain shareable, bookmarkable, refresh-safe, and compatible with browser navigation.7475## Handle Forms Separately7677Use native React state and framework form APIs for simple forms. Consider React Hook Form, Formik, or the project's established form abstraction for large or nested forms, dynamic arrays, field-level validation, performance constraints, or complex submission flows.7879## Review Checklist8081For each state value, verify:82831. Does it need to be state, or can it be derived?842. Who owns it: backend, URL, form, persistent storage, or the React application?853. Can it stay local or be lifted to a nearby parent?864. Is Context merely distributing a dependency, or being used as a high-frequency global store?875. Is a client store actually necessary, and are consumers using narrow selectors?886. Is backend data incorrectly duplicated outside its server-state cache?897. Are there multiple sources of truth or effects synchronizing state systems?908. Is one enormous global store mixing unrelated domains?919. Does persistence work through a clear abstraction without forcing global scope?9210. Does the choice align with the project's existing architecture?9394Choose the smallest tool that correctly models the state. The goal is not one state library or the fewest libraries; it is clear ownership and a single source of truth for every category.