A customer updates their delivery address, returns to checkout, and sees the old address. Another screen shows the correct one.
The API request succeeded. The problem is that the application now maintains several copies of the same information, each with a different update path.
This is a common architectural risk in React Native state management. When API responses, form drafts, navigation choices, and loading flags enter one undifferentiated store, developers inherit the responsibility of keeping everything synchronized.
Client state represents decisions and interactions controlled by the application. Server state represents remotely managed information that the application reads, caches, and updates. The distinction concerns authority and lifecycle, not simply where a value currently lives.
What Is Client State in React Native?
Client state describes information the app controls directly: an open bottom sheet, an unfinished search query, a selected tab, or an unsaved form.
Its scope can vary. A password-visibility toggle belongs to one component. A multistep registration draft may need to survive navigation across several screens.
A useful architectural default is to keep state close to the components that need it, expanding its scope when sharing or lifetime requirements justify that decision.
Not every calculated value needs storage. React explicitly recommends avoiding redundant and duplicated state. A filtered list or selected object can often be calculated from existing data and a small amount of interaction state. React’s state-structure guidance explains why this reduces synchronization errors.
For example:
const [selectedProductId, setSelectedProductId] =
useState<string | null>(null);
const selectedProduct = products.find(
product => product.id === selectedProductId
);
The selection is client state. The selected product is derived from the available product data.
What Is Server State?
Server state includes information such as order history, product availability, saved addresses, and backend-managed permissions.
The app holds a local representation, but another device, user, or backend process may change the authoritative record.
That introduces responsibilities beyond assigning a value:
- Fetching and identifying cached results.
- Tracking request progress and failures.
- Deciding when cached information needs refreshing.
- Reconciling writes with subsequent reads.
TanStack Query describes itself as a server-state library and explicitly distinguishes that role from local or global client-state management. Both approaches can coexist in one application. Its client-state comparison explains this separation.
An API response does not become client-owned information because it sits in Redux, Context, or device storage.Its authority remains elsewhere.
Client State vs Server State: What Belongs Where?
The following table provides practical starting points. Product requirements may change the answer, particularly for offline and collaborative applications.
| Information | Classification | Typical home |
|---|---|---|
| Modal visibility | Local client state | useState |
| Unsaved form values | Editable client draft | Component state or form manager |
| Shared onboarding draft | Shared client state | Reducer, Context, or client store |
| Search text and chosen filters | Client state | Screen state or navigation parameters |
| Results returned for those filters | Server state | Query cache |
| Orders and saved addresses | Server state | Query cache |
| Selected order ID | Client/navigation state | Screen state or route parameters |
| Selected order details | Server state | Query cache keyed by ID |
| Filtered results or display totals | Derived data | Calculation or selector |
| Authentication credentials | Security-sensitive session material | Appropriate secure-storage mechanism |
Two separate questions govern placement: who owns the value, and how long must this particular representation survive?
Which State-Management Tools Fit Each Responsibility?
For simple interactions, useState is usually sufficient. A reducer can help when related transitions need explicit rules. Context can distribute shared values, while a dedicated client store can support more involved cross-screen workflows.
For remotely managed data, a query library provides a more specialized abstraction.
An existing Redux application does not need to abandon Redux to make this distinction. Redux’s official guidance recommends RTK Query as its default approach to data fetching and caching. The Redux side-effects guide documents that recommendation.
A reasonable selection strategy is:
| Application need | Candidate approach |
|---|---|
| Small, isolated UI interaction | useState |
| Related local transitions | useReducer |
| Shared client preferences or workflow state | Context or an established client store |
| API caching in an existing Redux architecture | RTK Query |
| API caching independent of Redux | TanStack Query |
These are implementation choices, not a requirement to install every category. The aim is to give each responsibility one clear owner.
How Should Search Filters and API Results Work Together?
A search screen illustrates the boundary particularly well.
The user controls the search term. The backend supplies results for that term. Both participate in the same screen without needing the same storage mechanism.
The following abbreviated TanStack Query v5 example assumes an authenticated API helper and a configured QueryClientProvider:
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
function useProductSearch(accountId: string) {
const [searchText, setSearchText] = useState('');
const term = searchText.trim();
const query = useQuery({
queryKey: ['products', accountId, { term }],
queryFn: ({ signal }) =>
api.searchProducts({ accountId, term, signal }),
staleTime: 60_000,
});
return { searchText, setSearchText, query };
}
searchText represents user input. query.data represents cached server results.
The query key identifies the requested data. Variables that change the result, such as account, search term, page, or filter, belong in that identity. TanStack’s query-key documentation explains this dependency model.
A production search interface may debounce the term before querying. The one-minute freshness setting above is illustrative and should reflect the product’s requirements.
How Fresh Is Cached Server State?
Caching creates a local snapshot, not a guarantee that nothing has changed remotely.
In TanStack Query v5, queries are stale by default. Stale queries can refetch on configured lifecycle events, including mounting, focus, and reconnection.
Two settings have different jobs:
staleTimedetermines how long data is considered fresh.gcTimedetermines how long inactive cache entries remain before garbage collection.
The documented default garbage-collection period for inactive queries on the client is five minutes. Becoming stale does not immediately delete data or, by itself, trigger a request. TanStack’s important defaults describe these behaviors.
A product catalog and an order-tracking screen therefore need separate freshness decisions. One global setting rarely expresses every screen’s requirements.
What Happens When a User Edits Server Data?
Editing introduces a legitimate second representation: a draft.
A saved profile belongs in the query cache. The user’s unfinished changes belong in an editing session. They intentionally differ until submission succeeds.
An implementation should define when that draft starts and what happens if the underlying record changes during editing. Automatically resetting the form after every background refetch can destroy unfinished work.
After a successful mutation, the application can invalidate affected queries so active views retrieve updated information. TanStack documents this through mutation callbacks and invalidateQueries. Its mutation-invalidation guideprovides examples.
For a successful address update, an application-specific callback might include:
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: ['addresses', accountId],
});
}
Related checkout data may also require invalidation if the address affects delivery options.
Do Optimistic Updates Change Ownership?
An optimistic update displays the expected result before confirmation. It does not transfer authority to the client.
TanStack supports optimistic changes through the UI or query cache, with reconciliation and rollback strategies for failures. Its optimistic-update guide describes these patterns.
For example, a pending favorite toggle may appear immediately. The interface still needs to explain or reverse the change if the server rejects it.
What Is Different About React Native?
Mobile lifecycle events deserve explicit integration.
TanStack’s React Native guidance shows how to connect connectivity changes to onlineManager and app activity changes through React Native’s AppState to focusManager. It also discusses screen-focus refetching. The React Native integration guide covers these connections.
These events are distinct. Returning from the background and navigating back to a s




















Add Comment