Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An infinite refetch occurs when an error response is received when using useQueries. #4644

Closed
doumAb180 opened this issue Dec 15, 2022 · 7 comments · Fixed by #5271
Closed
Labels
bug Something isn't working help wanted Extra attention is needed package: react-query suspense

Comments

@doumAb180
Copy link

Describe the bug

An infinite refetch occurs when an error response is received when using useQueries.
However, when remove the suspense query option, an infinite refresh does not occur.
And it is a situation where the Errorboundary cannot catch the error.
It can be reproduced by correcting the request url to cause an error in the link below.

Your minimal, reproducible example

https://codesandbox.io/s/angry-diffie-rekf90?file=/src/query.ts:278-577

Steps to reproduce

  1. Go to example.
  2. Modify the request url.
  3. So you can see the infinite refetching.

Expected behavior

When using useQueries, I want the retry and suspense options to work properly and I hope the ErrorBoundary can catch errors well.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

mac os
chrome
108.0.5359.98

Tanstack Query version

v4.19.1

TypeScript version

v4.9.4

Additional context

No response

@TkDodo TkDodo added bug Something isn't working suspense package: react-query labels Dec 15, 2022
@TkDodo
Copy link
Collaborator

TkDodo commented Dec 15, 2022

interesting, thanks for reporting. I wonder why the same doesn't happen for useQuery. I think what's happening is:

  • query mounts, fetches, suspends
  • query errors, but we don't throw to the error boundary, so query re-mounts
  • erroneous queries are always considered stale, and since a component mounts, we fetch and suspend again.

There must be something in useQuery to prevent this that we haven't added to useQueries. I think it has something to do with retryOnMount, but we should set that to false in both cases:

) => {
if (options.suspense || options.useErrorBoundary) {
// Prevent retrying failed query if the error boundary has not been reset yet
if (!errorResetBoundary.isReset()) {
options.retryOnMount = false
}
}
}

@doumAb180
Copy link
Author

@TkDodo Thank you for your quick reply.

I tried many things by referring to your answer, but when I modified the retryOnMount to false, it worked correctly.
The problem seems to be that if the retry option is set to false, retry will not occur when the observer is mounted.

Anyway, your answer was very helpful. Thank you 🙇‍♂️ 😃

@TkDodo
Copy link
Collaborator

TkDodo commented Dec 15, 2022

yes, this is exactly what the retryOnMount flag is for. From the docs:

retryOnMount: boolean
If set to false, the query will not be retried on mount if it contains an error. Defaults to true.

I still think you, as a user, should not need to set that flag to false for yourself when using suspense. It works for useQuery, so it should also work for useQueries.

@chekrd
Copy link

chekrd commented Jan 26, 2023

I have prepared a failing unit test for this scenario #4882

@projectnatz
Copy link

projectnatz commented Mar 1, 2023

I already created a wrapper around the useQueries function for better handling types and queries.
By adding retryOnMount: errorResetBoundary.isReset() the infinite loading problem the problem looks fixed and the reset function on the ErrorBoundary does indeed retry the query.
Important: I use suspense: true by default.

/** @version 1.0.0 */
export function useQueries<Qs extends any[]>({ queries }: { queries: readonly [...{ [Key in keyof Qs]: Qs[Key] & GetOptions<Qs[Key]> }] }): QueryResults<Qs>
{
	const loads = React.useMemo(() => queries.map(options => Query.prepare(options.queryFn)), [])
	const errorResetBoundary = useQueryErrorResetBoundary() // <- get the error boundary QueryErrorResetBoundaryValue

	return useQueriesBase({
		// @ts-ignore
		queries: queries.map(
			(options, index) =>
			{
				const queryKey = options.queryKey
				const enabled = areValidArgs(queryKey)
				const load = loads[index]

				return {
					...Query.Options.get(options.queryFn),
					retryOnMount: errorResetBoundary.isReset(), // <- this line here
					...options,
					queryFn: enabled ? load : undefined,
					enabled,
					queryKey: enabled ? queryKey : undefined,
				}
			}
		),
	}) as QueryResults<Qs>
}

So a quick fix for users who use suspense: true could be:

import { useQueries as useQueriesBase, useQueryErrorResetBoundary } from "@tanstack/react-query"

export const useQueries: typeof useQueriesBase = options =>
{
	const errorResetBoundary = useQueryErrorResetBoundary()
	return useQueriesBase({
		...options,
		queries: options.queries.map(query => ({ retryOnMount: errorResetBoundary.isReset(), ...query })),
	})
}

@TkDodo TkDodo added the help wanted Extra attention is needed label Mar 5, 2023
@TkDodo
Copy link
Collaborator

TkDodo commented Mar 5, 2023

if someone wants to tackle this one, please do. The failing test case provided by @chekrd should be helpful:

bouncehead13 pushed a commit to bouncehead13/query that referenced this issue Apr 13, 2023
…e refetch

useQuery correctly handles checks on  error boundary before retry. This work will change useQueries to match behavior.

Fixes TanStack#4644
@bouncehead13
Copy link
Contributor

@TkDodo I gave this a shot in the dark. There were some clear differences with the order of operations between useQuery and useQueries.

More info in the PR. Let me know your thoughts!

TkDodo added a commit that referenced this issue Apr 15, 2023
…e refetch (#5271)

* fix(useQueries): check error boundary before retry to prevent infinite refetch

useQuery correctly handles checks on  error boundary before retry. This work will change useQueries to match behavior.

Fixes #4644

* style: fix formatting

---------

Co-authored-by: Hancock, Matthew <Matthew_Hancock@comcast.com>
Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed package: react-query suspense
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants