React Native State Management
A practical guide to choosing local state, Context, Redux, Zustand, and more.
State management questions are almost always really scope questions: how many places need this piece of data, and how often does it change? Here's the decision path I actually use.
Start With useState, Seriously
The default should be component-local `useState` or `useReducer` for anything that only one screen or one small component tree needs. I see teams reach for global state management for form input values or a modal's open/closed flag — state that has no business living outside the component that owns it. The cost isn't just unnecessary code; it's that every piece of state in a global store is something every other engineer now has to consider when reasoning about app-wide behavior.
Context: Good for Rarely-Changing, Widely-Read Values
React Context is the right tool for values that many components read but that change infrequently — theme, locale, an authenticated user object once it's loaded. It's the wrong tool for frequently-changing state shared across a big tree, because every consumer of a context re-renders when its value changes, and there's no built-in selector mechanism to opt individual components out of updates they don't care about. A theme toggle through context is fine. A frequently-updating cart total through context, feeding a large component tree, will cause re-render problems.
Redux Toolkit vs Zustand — Less Different Than the Debate Suggests
Both solve the same core problem: state that's genuinely global, needs to be read and written from unrelated parts of the app, and benefits from selective subscriptions so components only re-render when the slice they actually use changes. Redux Toolkit brings a more structured, opinionated pattern — slices, the DevTools time-travel debugger, a strong middleware ecosystem — which is valuable on larger teams where consistency across many engineers matters more than minimizing boilerplate. Zustand is lighter-weight, has almost no boilerplate, and is my choice on smaller teams or projects where Redux's structure would be more ceremony than the project needs.
I don't treat this as a philosophical choice. I look at team size, whether they already have Redux experience, and how much the app's state complexity actually justifies Redux Toolkit's structure versus Zustand's simplicity.
Server State Is a Different Problem — Don't Force It Into Your Store
Data that comes from an API — user profile, a list of products, anything fetched over the network — isn't the same kind of state as client-only state like 'is this modal open.' It has its own lifecycle: loading, error, staleness, caching, refetching, pagination. Cramming server data into Redux or Zustand and hand-rolling loading flags and cache invalidation is where I see teams lose the most time. React Query (or RTK Query if the team is already Redux-based) handles this properly out of the box — caching, background refetching, deduplication of in-flight requests — and it means your global client-state store stays focused on things that are actually client state.
The Decision in One Pass
Local to one screen → `useState`/`useReducer`. Read by many, changes rarely → Context. Genuinely global client state, read/written from unrelated screens → Redux Toolkit or Zustand, chosen based on team size and existing familiarity. Anything that came from an API → React Query or RTK Query, not your global store. Getting this split right early is one of the highest-leverage architecture decisions in a React Native app, because it's expensive to unwind later once dozens of components depend on the wrong pattern.
