"Stale-while-revalidate" is a caching strategy that makes apps feel instant: when you request data, immediately return whatever's in the cache (even if stale), then refetch in the background and update. Navigate back to a page and you see last time's data at once, refreshed a moment later. useSWR (the pattern behind the popular library) does this with a shared, module-level cache, request deduplication, and cross-component updates.
Implement useSwr(key, fetcher). Return { data, error, isValidating, mutate }. Serve the cached data for key immediately, revalidate in the background, dedup concurrent requests for the same key, and let mutate write the cache and notify every mounted component using that key.
function useSwr(key, fetcher) {
// returns { data, error, isValidating, mutate }
}
const { data, error, isValidating } = useSwr(`/api/user/${id}`, fetchJson);
if (error) return <Error />;
if (!data) return <Skeleton />; // no cache yet
return <Profile user={data} stale={isValidating} />;
// Optimistic update: write the cache now, revalidate after the mutation.
const { data, mutate } = useSwr('/api/todos', fetchTodos);
await saveTodo(todo);
mutate([...data, todo]); // update every component showing '/api/todos'
cache.get(key) synchronously (stale), then fetch and update. The cache is module-level, shared across all components.mutate(data?, revalidate = true) — optionally write data to the cache (optimistic) and re-fetch; returns a promise. Subscribe on mount, unsubscribe on unmount.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.