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

When using Suspense or throwOnError, React Query never tries to refetch failed query #8523

Closed
OliverJAsh opened this issue Jan 10, 2025 · 2 comments

Comments

@OliverJAsh
Copy link
Contributor

OliverJAsh commented Jan 10, 2025

Describe the bug

At Unsplash we have integrated React Query with SSR as per the official guide.

As per the guide, when a user performs a soft navigation from one route to another, we prefetch queries for the next route using prefetchQuery, in an event handler outside of React.

Immediately after, route components render using the very same queries, with useSuspenseQuery. When this happens, React Query never attempts to run the query function again if the query failed at the previous prefetch step.

Your minimal, reproducible example

https://stackblitz.com/edit/tanstack-query-qkrlvsny?file=src%2Findex.tsx&preset=node

Steps to reproduce

  1. Prefetch a query using prefetchQuery.
  2. Immediately after, render a component with the same query inside useSuspenseQuery.

Reduced test case here.

Another example of how this might happen is when we switch from one component to another, where both components use the same query. Reduced test case here.

Expected behavior

I would expect queryFn to run again when a new component tries to use the previously failed query for the first time, but it never does.

React Query seems to retrieve the previous error from its cache. This error is then thrown, thus triggering the error boundary.

As per the docs on Resetting Error Boundaries, we could add a button to reset the query error and error boundary (updated test case here). However, ideally this wouldn't require an interaction from the user, and the query would automatically retry when its used for the first time in a component. This is the behaviour we have with useQuery.

How often does this bug happen?

Often

Screenshots or Videos

No response

Platform

N/A

Tanstack Query adapter

None

TanStack Query version

5.63.0

TypeScript version

No response

Additional context

I think these issues are related, but I'm not familiar enough with React Query to know whether they're the same or slightly different:

@TkDodo
Copy link
Collaborator

TkDodo commented Jan 11, 2025

This is interestingly similar to:

Where @KATT and I concluded that it’s the “expected” behaviour as of now.

FYI, with our suspense integration, once a query errors, we need it to be displayed in the error boundary, where the query needs to be “reset” as shown in the docs: https://tanstack.com/query/latest/docs/framework/react/reference/QueryErrorResetBoundary

This usually isn’t a problem when useSuspenseQuery initiates the fetch, as it will then go to the boundary after it showed the suspense fallback.

When prefetching is involved, and that prefetching failed, what happens is that useSuspenseQuery picks up that failed promise and will throw it to the error boundary without retrying. So you see the error boundary, where the user will have to reset it, just as if useSuspenseQuery had failed.

Note that I really dislike the QueryErrorResetBoundary API we have at the moment, but it’s necessary because after the suspense boundary was rendered, react will immediately re-render the component once more before throwing to the error boundary to see if it can recover from that error.

So what we do is we “stop” any refetches that would happen from query mounting until the boundary has been reset. Otherwise, we could never get an error to be propagated to the error boundary, as the intermediate render would trigger another refetch and throw to the suspense boundary.

This is generally a quite complicated problem that I’m currently discussing with the react team because it also has implications on our upcoming use(promise) integration. For now, it is what it is.

@TkDodo TkDodo closed this as not planned Won't fix, can't repro, duplicate, stale Jan 11, 2025
@OliverJAsh
Copy link
Contributor Author

Thanks for taking the time to explain that. ❤

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants