FrontendPro

62Implement useQuery() with caching, retries, and stale data

mediumAbout 45 minutesCodingreacthookscachinguseSyncExternalStore

Problem

Implement a small version of React Query: useQuery(key, fetcher, { staleTime = 0, retry = 2, retryDelay = 10 }). It returns { data, error, status, isFetching, refetch }, where status is "loading", "success" or "error".

The cache is shared by every component, keyed by the string key:

  • If the cache has data, return it immediately. If that data is older than staleTime ms, also refetch in the background (stale-while-revalidate) and set isFetching to true.
  • Several components asking for the same key at the same time cause one request.
  • A failing fetcher is retried up to retry times, waiting retryDelay * 2 ** attempt ms between attempts. After the last failure, status is "error", unless older data exists, which stays visible.
  • When a fetch completes, every component using that key re-renders with the new data.
function UserBadge({ id }) {
  const { data, status } = useQuery(`user:${id}`, () => api.getUser(id), { staleTime: 30_000 });
  if (status === "loading") return <Skeleton />;
  if (status === "error") return <span>Unavailable</span>;
  return <span>{data.name}</span>;
}

Try it yourself

Write your solution, run it, then submit to check it against the tests.

App.jsxReact + DOM

Step-by-step

A module-level Map from key to an entry: { data, error, updatedAt, promise, isFetching, version, listeners }. Living outside React is what lets every component share it.

Unlock the full solution

What's inside

  • Step-by-step
  • Approach
  • Solution
  • Complexity
  • Edge cases
  • Follow-up questions
  • Tests

Includes 2 code listings, 5 edge cases, 4 follow-up questions.

One-time payment by UPI, card or net banking. Launch price.

All 150 answersOne payment, yours forever