Shopify/shopify-frontend-template-react

Fetch does not throw by default, leading to inconsistent behaviour from react-query

jmunozz opened this issue · 1 comments

Fetch does not throw by default, leading to inconsistent behaviour from react-query

Expected behavior

I want to use react-query isError on HTTP errors like 4XX, 5XX...

Actual behavior

Fetch does not throw by default so we have to check response status before going on. React-query recommends to use like below:

useQuery({
  queryKey: ['todos', todoId],
  queryFn: async () => {
    const response = await fetch('/todos/' + todoId)
    if (!response.ok) {
      throw new Error('Network response was not ok')
    }
    return response.json()
  },
})

Instead we do not check fetch response in hook:

export const useAppQuery = ({ url, fetchInit = {}, reactQueryOptions }) => {
  const authenticatedFetch = useAuthenticatedFetch();
  const fetch = useMemo(() => {
    return async () => {
      const response = await authenticatedFetch(url, fetchInit);
      return response.json();
    };
  }, [url, JSON.stringify(fetchInit)]);

  return useQuery(url, fetch, {
    ...reactQueryOptions,
    refetchOnWindowFocus: false,
  });
};

One solution would be forcing fetch to throw on HTTP errors.

experienced the same issue, changed my code to:

  const authenticatedFetch = useAuthenticatedFetch();
  const fetch = useMemo(() => {
    return async () => {
      const response = await authenticatedFetch(url, fetchInit);
      if (!response.ok) {
        throw new Error(`failed fetch (${url})`)
      }
      return response.json();
    };
  }, [url, JSON.stringify(fetchInit)]);

  return useQuery(url, fetch, {
    ...reactQueryOptions,
    refetchOnWindowFocus: false,
  });
};

Do note this kicks in default query retries (3) see https://tanstack.com/query/v4/docs/react/guides/query-retries if you haven't specified your own option.