liveBook · Manning

Caching

As explained in React in Depth

A cache is a stored copy of retrieved or computed data that can be returned without obtaining or calculating it again.

A remote-data cache keeps local copies of server results so a React application can reuse data instead of waiting for every request. TanStack Query manages loading, refreshing, and invalidation; a query can return cached data when it is fresh enough. Caching does not remove the need to decide what happens when a mutation changes server data. section 9.5 section 9.3.2

Choose the cache update that fits what the mutation returns:

  • Invalidate affected queries when their results may be stale. Query keys identify the results to refresh: after deleting a customer, a prefix can target customer lists while a specific key targets that customer. section 9.3.2
  • Write a successful mutation response directly into a cached query when the API guarantees which resource changed and returns its updated value. Components using that query re-render without an additional fetch for every mutation. section 9.4.1
  • For a faster perceived response, use an optimistic update while the request is pending, then replace the provisional value with the server result. Alternatively, display existing partial data while the full response loads. section 9.5 section 9.4.3

Update the query that a mutation changed

If an API mutation returns the updated detail record, its useMutation onSuccess callback can call queryClient.setQueryData(["currentThing", { id }], newThing). A list view needs a different callback: update the matching entry under ["things"] rather than replacing the detail query. Passing the callback into a shared mutation hook keeps that distinction at the caller. section 9.4.1

Listing 9.13 Updating cache directly from a mutation
// useDoThing.js (excerpt)
function useDoThing(onSuccess) {    #1
  const { mutate: doThing } = useMutation({   #1
    mutationFn: API.doThing,   #1
    onSuccess,   #1
  });    #1
  return doThing;
}
//
// useThatThing.js (excerpt)
const onSuccess = (newThing) =>      #2
  queryClient.setQueryData(    #2
    ["currentThing", { id }],   #2
    newThing,    #2
  );   #2
const doThing = useDoThing(onSuccess);
//
// useThisThing (excerpt)
const onSuccess = ({ name, done }) =>     #3
  queryClient.setQueryData(     #3
    ["things"],      #3
    (oldThings) =>    #3
      oldThings.map((oldThing) =>     #3
        oldThing.id !== id     #3
          ? oldThing     #3
          : { id, name, count: done.length }    #3
      )
    );
const doThing = useDoThing(onSuccess);

Compare the detail-query replacement with the list-query mapping; the same mutation hook accepts the appropriate onSuccess callback. section 9.4.1

Cached list data can also seed a detail query. Read the known fields with getQueryData, supply placeholders for missing fields, and pass the assembled object as useQuery initialData. The detail view renders immediately, then renders the complete server response when it arrives. Placeholders improve perceived speed but should not be mistaken for complete data. section 9.4.3

Listing 9.15 A query with placeholder data (excerpt)
function useThatThing(id) {
  ...
  // Find what we already know about this thing
  const queryClient = useQueryClient();
  const initialData = useMemo(() => {
    const things =
      queryClient.getQueryData(["things"]);     #1
    const { count, ...partialThing } =    #1
      things.find((t) => t.id === id);    #1
    return {    #1
      ...partialThing,    #1
      description: "...",    #2
      done: Array.from(Array(count))     #3
        .map((k, id) => ({ id })),    #3
    };
  }, [id, queryClient]);
  const { data: thing } = useQuery({

    queryKey: ["currentThing", { id }],
    queryFn: () => loadThing(id),
    initialData,    #4
  });
  ...
}

The hook builds initial detail data from the cached list, filling absent fields until the detail request completes. section 9.4.3

How React in Depth covers it

How deep it goes
Works through query invalidation, mutation-driven updates, and partial initial data in hooks; leaves freshness policy details unspecified.
Examples
Uses customer deletion, an updated detail record, and cached list fields that seed a detail view.
What it assumes
Assumes React hooks and server-facing functions; shows how to attach query keys, mutation callbacks, and cache operations.
What you can do after
Apply it via TanStack Query to invalidate affected results, update cached queries after mutations, and prefill detail views.
How it connects
Connects query keys and invalidation with mutations, optimistic updates, initial data, and loading states.

Also explained in

Compare how 38 books explain caching →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of React in Depth. The section links point to the parts of the book it draws on.