React-Query in custom hook is being triggered multiple times

Viewed 20

Sandbox code: https://codesandbox.io/s/nextjs-react-query-9thcky

Hi, I have wrapping component that uses custom hook with react-query to fetch the data and exposes that data, as well as isLoading and isError state. Within the wrapping component as long as query is being loaded the whole page should not be rendered. If query fails I want to pass the failover object from the hook.

There's component that's within children of that wrapper that uses the same custom hook, but I would expect it to not need to care about isLoading state instead either get data from successful request or failover data if request fails.

I see what's going on, that the custom hook runs the react-query again and it provides undefined data to the component that uses it. Is it expected behaviour? Is it pattern that I can only achive by using context API? (I wanted to switch to react-query but it doesn't seem to work as I'd expect it).

Can someone explain me this behaviour like I'm fine, because I'm either to dumb or just sit on it for too long :) Really appreciate any help.

P.S. Yes I know I use index as a key in the sandbox but it's not about it :)

I tried different useQuery options, like turning on refetching at all but it still behaves like the custom hook that's being render later on just doesn't have access to the cache and just starts the whole query over again.

1 Answers

react-query only caches successfully fetched data. Your query goes into error state and has no data internally, which means it is considered stale and will try to refetch data as soon as a new component mounts.

So when the child mounts, your query will go back to isLoading state because it is fetching data and it doesn't have any data internally.

It's hard to say what you are trying to achieve with this, but you can:

  • use placeholderData to show data while you are loading
  • destruct data with a default value to always have data:
const { data = FAILOVER_DATA } = useQuery(...)
  • make sure your query doesn't go into error state by returning FAILOVER_DATA from the queryFn if the fetch failed, as it seems to me you want to treat FAILOVER_DATA like any data that comes from the api.
  • always return data if you don't have data and not check the isError flag, because the query goes back to loading state:
return {
  data: data ?? FAILOVER_DATA,
  isLoading,
  isError
};
Related