How to get pending component to show instead of stale data with loader + query
Currently when loading data with ensureQueryData + useSuspenseQuery it will show the loading component the on first load. However if the query is invalidated, subsequent loads show the stale data instead of the pending component again. The route is also not preloaded the second time.
I'd like to show the pending component to avoid showing stale data, as well as allow the route to preload.
18 Replies
rare-sapphire•2mo ago
You can likely reset the query and then invalidate the route.
Suspense by default will only trigger when you don’t have a cache entry already, so clearing the query cache will trigger the suspense query, and invalidating the router will cause it to run on preload again
helpful-purpleOP•2mo ago
Will try this out tomorrow thanks!
Running into a situation where using either resetQueries or removeQueries in my optimistic mutation is causing CancelledErrors on slow connections. And invalidated queries causes stale data to show temporarily.
I have a list of data that can be both filtered and sorted. When a user favorites an item I optimistically update it, and invalidate favorites, however on slow connections when switching to the favorites tab the stale data shows with no indicator that it is fetching the new data
absent-sapphire•2mo ago
cc @TkDodo 🔮
subsequent-cyan•2mo ago
Can I see a reproduction please?
helpful-purpleOP•2mo ago
yep will put one together
https://stackblitz.com/~/github.com/alex-delia/router-bug-recreation?file=src/routes/_postsLayout.posts.tsx
here is a reproduction. Ive setup the queries to simulate a slower network, and set the minimum loader time to 2000ms.
On the posts page, each tab shows the loader on initial navigation. If you load them all, then add an item to favorites and switch to the favorites tab, there is always a delay between the old data showing and the new data being added, with no method of visually seeing that data is being loaded
subsequent-cyan•2mo ago
there is always a delay between the old data showing and the new data being addedthat's because your optimistic update only changes the entry of the
tag you're currently in, and it doesn't update the tag:favorites. If you want that, you need to apply the optimistic update to all the cache entries where you think it's necessary / will have an effect. That's kind of the drawback of optimistic updates: you have to re-implement what the server does on the client.
with no method of visually seeing that data is being loadedyou can always check
isFetching and show a background pending indicator ....
you can also switch the route loader to await queryClient.fetchQuery if you don't want stale data to be shown, as that would show the route's pending component when data is stale, as fetchQuery respects staleTime and will only immediately return fresh data from the cache, while ensureQueryData will give you whatever it has in the cache without blockinghelpful-purpleOP•2mo ago
would isFetching be on the suspenseQuery?
I did try fetchQuery because I thought that could be the answer but even with fetchQuery its still showing the stale data instead of the pending component for some reason.
subsequent-cyan•2mo ago
Yes
helpful-purpleOP•2mo ago
is it a bug then that fetchQuery is not retriggering the pendingComponent?
subsequent-cyan•2mo ago
It respects staleTime
helpful-purpleOP•2mo ago
I have staletime on the route + query set to 0 & I am manually invalidating the query on mutation, but still not retriggering pending component
subsequent-cyan•2mo ago
That should work
In your example you were using ensureQueryData, which will never re-fetch
helpful-purpleOP•2mo ago
I did try swapping jt out as well, can update the example for you
https://stackblitz.com/~/github.com/alex-delia/router-bug-recreation
Here is the example updated to use fetchQuery as well as setting staleTime to 0 everywhere. I also even added router.invalidate() to the onSettled just to test.
subsequent-cyan•2mo ago
@Manuel Schiller can probably answer this better but I think the router won't re-suspend once it has data
absent-sapphire•2mo ago
resuspend when ?
subsequent-cyan•2mo ago
ah, you can do:
absent-sapphire•2mo ago
yes
by default loader runs detached when invalidating
helpful-purpleOP•2mo ago
Ahhh that’s the property that was missed. Will try this out
invalidating the router with forcePending: true, seems to only cause the current active route to enter pending state, but not other routes that were invalidated after navigating to them.