Seth Lutske
Seth Lutske

Reputation: 10772

React query not updating data even after refetch shows new data from api

I am using react query to fetch a list of items. After creating a new item, I am calling refetch on my query to get the updated list. I see a new api call is made, and the new item I just created is returned as part of the api response. However, react-query is not updating its data value.

My code has a useQuery wrapped in a hook to be able to be used in multiple places, as the query fn and its dependencies are complex:

// simplified version of the useQuery:

export const useItemsQuery = (search = "") => {
  const { user } = usePermissions();
  const filter = useStore((state) => state.projects.filter);

  const projects = useQuery({
    queryKey: [
      "Items list",
      `Items by ${filter}`,
      `User: ${user.id}`
    ],
    queryFn: () => complexQueryFunction(filter, user.id)
  });

  return projects;
};

In a few other components

// Component 1
const items = useItemsQuery()

items.data.map(...etc)
// Component 2
const items = useItemsQuery()

items.data.find(...etc)

The most confounding this is that even if I do into my react-query devtools and manually click "invalidate", the api call is made, and a new list is fetched. I can see that the data in the api call does not match the data in the react query devtools:

In the api call, 10 items:

enter image description here

In the react query devtools, where I clicked "invalidate" that caused the above api call, 9 items:

enter image description here

I find it bizarre that not only calling refetch or queryClient.invalidateQuery({queryKey: [<the query key>]}) calls the api correctly and gets new data, but using the actual react-query devtools calls the api and gets the new data, but the data in reat-query's cache is not updated.

What might be causing this? Someone mentioned in another question that if you had mutated the data directly in place, react-query will not work properly and not update the cache. I checked my code and I don't believe this is the case. What else might be causing react-query to not update its .data to the value coming from the network call?

Upvotes: 5

Views: 1773

Answers (1)

Ian Carter
Ian Carter

Reputation: 2169

Problems like this are tricky and can have multiple causes:

1. exclude accidental mutation

If items.data is mutated directly, React Query won’t update. Try freezing it to catch any unwanted mutations:

useEffect(() => {
  if (items.data) Object.freeze(items.data);
}, [items.data]);

2. ensure query key consistency

If user.id or filter changes unexpectedly, cache behavior can break - log it:

console.debug("Query Key:", ["Items list", `Items by ${filter}`, `User: ${user.id}`]);

3. force React Query to detect changes

If the API returns the same object reference, React Query won’t register a change. Force a shallow copy:

const projects = useQuery({
  queryKey: ["Items list", `Items by ${filter}`, `User: ${user.id}`],
  queryFn: () => complexQueryFunction(filter, user.id),
  select: (data) => [...data],
});

4. ensure refetch actually returns the new item

Log the result of refetch():

const { refetch } = useItemsQuery();

useEffect(() => {
  refetch().then(({ data }) => console.log("Refetch result:", data));
}, []);

5. force stale data removal before refetching

set staleTime: 0 and gcTime: 0 to evict cache before refetch:

const projects = useQuery({
  queryKey: ["Items list", `Items by ${filter}`, `User: ${user.id}`],
  queryFn: () => complexQueryFunction(filter, user.id),
  staleTime: 0,
  gcTime: 0,
});

6. ensure mutations invalidate the query

If you're using a mutation, manually invalidate the query:

const mutation = useMutation(createNewItem, {
  onSuccess: () => {
    queryClient.invalidateQueries(["Items list"]);
  },
});

... or optimistically update:

onSuccess: (newItem) => {
  queryClient.setQueryData(["Items list"], (oldData) => [...oldData, newItem]);
}

7. devtools could be buggy (paranoia!!)

log the actual data instead of trusting devtools:

useEffect(() => {
  console.log("Current Query Data:", items.data);
}, [items.data]);

if refetch logs the correct data but the UI doesn’t update, it's likely a stale cache issue.

8. check your component

  • remove any useMemo or useCallback or React.memo to see if it then updates as expected
  • context and store lib (e.g. zustand/redux) with useStore might use a shallow comparison ((state) => state.items), React might not detect update
  • check state is depending on items.data
// log renderings to ensure your state updates are being picked up 
useEffect(() => {
  console.log("Items Data Updated:", items.data);
}, [items.data]);

Upvotes: 0

Related Questions