Mobile State Management
State management in mobile apps means juggling several distinct kinds of state at once: ephemeral UI state, app-wide global state, remote server data, and state that must survive app restarts. The most common architectural mistake is treating them all the same — cramming server data into a global store, or hoisting UI state higher than it needs to go.
The guiding rule: keep state as local as possible, reach for global state only when data is genuinely shared, and treat server state as its own category (with caching, refetching, and loading/error handling) rather than hand-managing it in a global store.
TL;DR
- Keep UI state local when possible.
- Use global state for genuinely shared data.
- Treat server state as its own thing (React Query / caching).
- Persist critical state to survive restarts; handle offline.
Quick Example
Local state is the default — useState (RN) / StatefulWidget (Flutter):
State Types
- Local — component-only (
useState,StatefulWidget). - Global — app-wide (Redux, Provider, BLoC).
- Server — remote data (React Query, SWR) — needs caching/refetching.
- URL/navigation — route parameters.
- Persisted — survives app restarts (AsyncStorage, SharedPreferences).
Use global state for: authentication, app settings/preferences, shopping cart, real-time data shared across screens, theme/locale. Most other state should stay local.
React Native Patterns
For server state, use TanStack/React Query rather than stuffing API data into Redux — you get caching, refetching, and loading/error states for free:
Flutter Patterns
Persistence
Persist only what should survive restarts (auth tokens, cart, preferences):
⚠️ Don't persist sensitive secrets in plain storage — use secure storage (Keychain/Keystore) for tokens and credentials.
Best Practices
- Keep state local first; lift it only when sharing demands it.
- Separate server state (React Query/SWR) from client/global state.
- Persist selectively — whitelist what truly needs to survive restarts.
- Use secure storage for tokens/secrets, not plain key-value stores.
- Handle offline and error states explicitly — assume the network can fail.
Common Mistakes
Putting server data in a global store
Over-globalizing UI state
FAQ
What's the difference between client state and server state?
Client state is owned and mutated entirely by your app — UI toggles, form inputs, the current theme. Server state is a cache of data that actually lives on a backend — user profiles, lists, anything fetched over the network. They have different needs: server state requires caching, background refetching, staleness handling, and loading/error states, which is why dedicated tools (React Query, SWR) exist. Conflating them — managing server data in a global client store — is the most common state mistake.
Do I need Redux, or is Context enough?
Context is fine for low-frequency global state like auth, theme, or locale — values that don't change often. It's not ideal for high-frequency updates (every change rerenders all consumers) or complex state logic. Reach for Redux Toolkit (or Zustand, which is lighter) when you have substantial shared state with complex updates. For server data, neither — use React Query. Match the tool to the state's nature and update frequency.
Provider, Riverpod, or BLoC in Flutter?
Provider is simple and well-established (ChangeNotifier + notifyListeners). Riverpod is the modern evolution — type-safe, testable, decoupled from the widget tree — and a strong default for new apps. BLoC suits teams wanting strict, event-driven structure and clear separation of business logic. All work; pick one and apply it consistently. For small apps, plain setState may suffice.
What state should I persist across app restarts?
Persist state that users expect to survive: authentication tokens, cart contents, user preferences/settings, and any in-progress work you don't want them to lose. Don't persist transient UI state or server data you can refetch. Use a whitelist (redux-persist) to be deliberate, and store sensitive values (tokens, credentials) in secure storage (Keychain/Keystore), not plain AsyncStorage/SharedPreferences.
Related Topics
- React Native — React Native development
- Flutter — Flutter development
- Mobile Navigation — Navigation state
- State Management — Web-side patterns
- Mobile Development — The hub