Why cache request results?
What does "caching request results" mean?
Caching is the temporary storage of request results, so that a repeated request for the same data does not trigger a new HTTP request, but instead uses the data already obtained from memory.
Example:
// Without cache - a new request every time
await fetch('/api/products');
// With cache - use the stored result if it's still valid
cache.get('/api/products') ?? fetch('/api/products');Why cache at all?
1. Speed (a faster UI)
Every request to the server:
- takes time (even 100-300 ms is already noticeable);
- causes extra renders, "flickering" loaders;
- can be expensive (a database, a third-party API).
When you cache a result, repeated requests for the same data:
- arrive instantly from memory (RAM);
- don't show a loader;
- create the feeling of a "reactive" interface, like in native apps.
The user switches instantly between pages and tabs without reloading.
2. Reduced server load
Without a cache, 100 users opening /products make 100 requests.
With a cache, there's one request, and the rest get the data locally.
The result:
- less traffic,
- lower latency,
- cheaper infrastructure,
- the API lasts longer without overload.
3. Fewer "loading" states
When you navigate between pages and come back:
- without a cache → "Loading..." again,
- with a cache → the data already exists, the UI renders instantly.
This sharply improves UX (the perceived "speed" of the interface).
4. Offline and "stale-while-revalidate" modes
A cache lets you:
- show old data offline (for example, when the network is lost),
- update data in the background without blocking the user.
This pattern is called Stale-While-Revalidate (SWR):
- Show the stale (cached) data instantly.
- Send a request for fresh data in the background.
- When the new data arrives, update the UI.
5. Avoiding "duplicate requests"
If component A and component B make the same request at the same time:
fetch('/api/user')
fetch('/api/user')without a cache, the server gets two requests. With a cache (or a library like React Query), there's only one request, and both components get the same result from the cache.
This is called deduplication.
6. Optimizing UX during navigation
If you:
- opened the list page (
/products), - then went to a product card (
/products/42), - and then went back,
without a cache, the list page loads from scratch again. With a cache, the list is already in memory, and React shows it instantly.
How to cache in React in practice
1. Manually via Map or localStorage
const cache = new Map();
async function fetchWithCache(url) {
if (cache.has(url)) return cache.get(url);
const res = await fetch(url);
const data = await res.json();
cache.set(url, data);
return data;
}Pros: simple, it works. Cons: no invalidation, stale data, duplicated logic.
2. Via React Query (TanStack Query)
The modern standard for caching data in React applications:
import { useQuery } from '@tanstack/react-query';
function User({ id }) {
const { data, isLoading } = useQuery({
queryKey: ['user', id],
queryFn: () => fetch(`/api/users/${id}`).then(r => r.json()),
staleTime: 5 * 60 * 1000, // 5-minute cache
});
if (isLoading) return <p>Loading...</p>;
return <p>{data.name}</p>;
}React Query:
- caches data in memory (
QueryClient); - performs deduplication;
- manages
staleandrefetch; - automatically refetches on tab focus;
- lets you set
staleTime,cacheTime,refetchOnMount, and more.
3. Via SWR (by Vercel)
A lightweight library built on the Stale-While-Revalidate concept:
import useSWR from 'swr';
const fetcher = url => fetch(url).then(r => r.json());
function User({ id }) {
const { data, error, isLoading } = useSWR(`/api/users/${id}`, fetcher);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error...</p>;
return <p>{data.name}</p>;
}SWR automatically:
- caches data by key (
/api/users/${id}); - refreshes background data when you return to the page;
- lets you use
mutate()to manually update the cache.
4. Persisted cache (keeping the cache between sessions)
React Query, SWR, and Apollo Client support a persisted cache:
- it saves the cache to
localStorageorIndexedDB; - on app restart, the data is available instantly;
- an API request runs in the background to sync.
SUMMARY
| Reason | Why cache |
|---|---|
| Speed | Instant display of data without loaders |
| UX | A stable interface when navigating and coming back |
| Network optimization | Fewer requests → lower latency and load |
| Deduplication | One request, many consumers |
| The SWR approach | Shows the old data → updates with the new |
| Offline | You can work without a network |
| Resilience | Even on a network error, UX doesn't break |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.