'ReactQuery - useInfiniteQuery refetching issue

I have implemented infinite scroll on a project that is using React Query library.

So far so good. Everything works as expected using the useInfiniteScroll hook

One issue that I am encountering is the caching mechanism of this library. If I query for a resource, ex: GET /posts/, will trigger a GET /posts/?page=0, scroll a bit down, get the next results, GET /posts/?page=1 which is totally fine. If I add search parameter to the page will do a GET /posts/?filter=someValue&page=0. All fine... but when I remove the filter from the search it will automatically do GET /posts/?page=0 & GET /posts/?page=1

A solution is to remove the query from the cache using the remove() method from the query itself. But this means that I have to manually do it for each query.

I would like to get a better solution that will cover all cases. I have a queryWrapper where I want to handle this.

I tried using the queryClient instances invalidateQueries and resetQueries but none seems to be able to remove it from the cache...

In the examples below I keep a ref for the params, if they are changed I can trigger the query to reset via useLayoutEffect hook. This part works as expected

invalidateQueries attempt

queryClient.invalidateQueries(
    [queryKey, JSON.stringify(paramsRef.current)],
    {
      exact: true,
      refetchActive: false,
      refetchInactive: false
    },
    { cancelRefetch: true }
);

resetQueries attempt

queryClient
    .resetQueries([queryKey, JSON.stringify(paramsRef.current)], {
      refetchPage: (page, index) => index === 0
    })

I even tried the queryClient.clear() method which should remove all existing queries from the cache but still the page number somehow remains cached... I access the queryClient using useQueryClient hook. If I inspect it, I can see the queries inside.

Can someone please help me to sort this cache issue Thanks!



Solution 1:[1]

but when I remove the filter from the search it will automatically do GET /posts/?page=0 & GET /posts/?page=1

This is the default react-query refetching behaviour: An infinite query only has one cache entry, with multiple pages. When a refetch happens, all currently visible pages will be refetched. This is documented here.

This is necessary for consistency, because if for example one entry was removed from page 1, and we wouldn't refetch page 2, the first entry on page 2 (old) would be equal to the last entry of page 1 (new).

Now the real question is, do you want a refetch or not when the filter changes? If not, then setting a staleTime would be the best solution. If you do want a refetch, refetching all pages is the safest option. Otherwise, you can try to remove all pages but the first one with queryClient.setQueryData when your query unmounts. react-query won't do that automatically because why would we delete data that the user has scrolled down to to see already.

Also note that for imperative refetches, like invalidateQueries, you have the option to pass a refetchPage function, where you can return a boolean for each page to indicate if it should be refetched or not. This is helpful if you only update one item and only want to refetch the page where this item resides. This is documented here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 TkDodo