-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Enabling a disabled query does not unsuspend #8499
Comments
I tried switching to a conditional
This works a bit better - the component renders with However, it still doesn’t trigger the fetch. The reason is that because a cache entry exists already, we can’t trigger the fetch during render without violating the rules of react: query/packages/react-query/src/useBaseQuery.ts Lines 146 to 150 in 6c2a055
The only thing that works right now is to pass the https://codesandbox.io/p/devbox/hopeful-flower-f6t8qp?workspaceId=ws_XiBCv7MgHSszKyXHXG5ray @KATT what do you think ? If we changed our code to call |
I don't have many opinions really, but I do have observations. Your explanation why this is happening is great and makes total sense, but if you only look at the public API, this still seems like a bug. I do think avoiding observable side effects in render is something we should strive for though, so where does that leave us? On the one hand, maybe this should lead us to question the current implementation, why are we triggering the fetch in the observer and not on the outside of it? I do think Suspense has been pushing the current RQ implementation for a while now. (It's interesting that On the other hand, I think we have something like three cases:
I don't have strong arguments why exactly, but I am starting to feel the current model/implementation chafing a bit. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Oh yeah, it's because the Agreed this is a bug |
FWIW I agree this specific bug is a bit niche and there's indeed a good userland workaround, hoist the |
I don't know about the internals of the library but I believe this is how it should work:
|
By the way I found another workaround for userland, I am sharing it here: In short, it consists on issuing a refetch if the query becomes enabled and hasn't been fetched before: if (enabled && isPending) refetch(); Probably has its issues, point them out if needed. |
Also, in case context helps, what I am trying to do is simply extending my hooks to be able to do this: const { data: user } = useQuery(...).suspense(); suspense function is basically a shortcut to: React.use(useQuery(...).promise) So then I have my custom hooks and can use them with or without suspense: const user = useUser().data; // user might be null
// or
const user = useUser().suspense().data; // user cannot be null Then I can easily use suspense but with parallel fetching: // Start both queries
const userQuery = useUser();
const articlesQuery = useArticles();
// Suspend until both queries have data
userQuery.suspend();
articlesQuery.suspend();
// Natively it would have been:
React.use(Promise.all([userQuery.promise, articlesQuery.promise])); The thing is that all this logic works inside hooks, I cannot create suspense boundaries to make it work. |
@hector what you describe is not how it works. In the second render, enabled is true, but fetching will happen in an effect. That effect never executes because
@Ephem I think I disagree here. The cache entry could definitely be observed by a different component, for example, the devools will show it. We could try to bend the rules here but I’m not really a fan. Generally, it seems that relying on I think all of this would be easier for us if I’m all in all more inclined to leave this pattern as-is, and document it, or even go the opposite direction and remove |
@TkDodo I see, thanks for the explanation.
What if you did not create the cache entry for a disabled query? Seems like it would work fine then. |
I need to think about this issue some more, but, I kinda think that we should have a I'm not convinced what the right thing to do is but I fixed it so it works according to current expectations in #8501. |
This is very true, I was thinking nothing could be observing the data in this specific circumstance, but you are right the query itself could be observed.
It is only an anti-pattern if you have not prefetched the query elsewhere, which is the common pattern with loaders. So if we want to at some point deprecate
Can you remind me about the reason again? I know there are some implementation trickiness involved here, but I kind of think we should support this long term if we can. I've been struggling with this myself, how would we solve dependent queries with Suspense otherwise? I don't think I've seen a good pattern currently. To be fair I think this is trickier with
@KATT Yes! I think this makes perfect sense. Trying to read from a disabled query does feel like it should be an error. Since a common reason for disabling a query is that it's a dependent one, it makes sense to me to have to make that check both when you declare the fetch and when you try to read. This also solves the type issue that data should always be defined with Suspense. |
Yes, the not supported part I was referring to is expecting this combo to trigger a fetch, which we currently do with the So if we get rid of
You’d expect TypeScript to give you
The suspense drawback that it creates waterfalls works to our advantage here. A simple dependent query with suspense is just ... calling
see that we can just access
Yeah, you can just not I think the user-land workaround @hector showed is exactly that:
triggering a fetch inside render when you know you’re going to suspend. But again, I think it’s dangerous for us to do this in the lib itself. |
Sounds fine in theory, but it’s not how react-query works. We couldn’t return anything from |
For sure, I'm definitely discussing several things here. API design/optimal behaviour and pragmatic/reasonable solutions might differ.
Ah, of course, thanks for clarifying! I do agree this is limiting and surprising though so if we could fix this, I think that would be optimal.
I definitely think it's hard, and maybe not worth it, but I do think it should be possible. One way could be to queue the fetch in render, but execute it elsewhere (higher up/outside the render tree)? That does also seem like a more robust model in general with Suspense? This is complex of course. The component has to create the promise since it needs to be Might not be worth it just for this and it's definitely not a short term thing, but I remember seeing other issues that might benefit from separating the promise from the fetch, so there might be more reasons to do this.
If we fail the
This is a super nice thing about suspense, but, what if I don't want to make the second query at all? The I haven't mentioned this in the thread, but I do have the exact situation @hector is reporting about here and I was hoping using Just wanted to add some extra context on usecases. 😄 |
that’s certainly interesting - so you think writing to a context / outside store during render that is not observed by any react component would be fine?
yes, conditional return types could do this I think, but it’s complex. The longer term goal though would be to deprecate / get rid of
I think right now, you’d have to conditionally render a child component. |
Describe the bug
I am using the new mechanism to suspend explained here: https://tanstack.com/query/latest/docs/framework/react/guides/suspense#using-usequerypromise-and-reactuse-experimental
Disabled queries return a pending promise (which is ok), but the promise does not resolve when the query is enabled afterwards.
This happens because the query is not refetched when enabled changes from false to true.
Your minimal, reproducible example
https://codesandbox.io/p/devbox/mystifying-mopsa-qwhjwx?workspaceId=ws_5WeinpZuX6zrSSrhdSgo5C
Steps to reproduce
Click the button to enable the query
Expected behavior
When the query is enabled it should fetch and the promise should finally resolve
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
Tanstack Query adapter
react-query
TanStack Query version
@tanstack/[email protected]
TypeScript version
[email protected]
Additional context
No response
The text was updated successfully, but these errors were encountered: