You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Redundant prefetches on pages with a prefetch next-15
Due to the changes to the client-side router with latest Next-15 update, pages that had a prefetch in them, re-run on every page request resulting in a bunch of redundant prefetches running on the server and none of the subsequent queries hydrating the client query cache.
Inconsistency with the query.state.dataUpdatedAt value
I'm unaware of the true implications that this could have but I found this out while debugging the first issue. The query.state.dataUpdatedAt values are inconsistent across versions and environments.
This issue can be reproduced by trying out the rsc-rq-prefetch demo in the trpc/examples-next-app-dir repository which was upgraded to Next-15, two days ago.
Install and run both the version, in the dev and prod environments
Observer the logs as you navigate with the links.
Additional information
More on Issue 1
I am not sure if the subsequent prefetches on navigation are meant to be sent down to the front-end, or even be triggered again in the first place.
Although, I think this new behaviour could be helpful if the prefetched query is sent down and hydrated in the front-end. Which lead me down a path to get this behaviour to work. My initial plan was to the set the default garbage collection time to 0, leading to queries being removed from the cache when there aren't any observers left. This did yield the result and the prefetched queries were successfully hydrating into the client query cache. But this resulted in a horrendous fallback UI to appear on every navigation.
Eventually, I had a look around in react-query docs regarding hydration and came across this limitation regarding hydration. Please correct if I'm wrong. I'm assuming that the HydrateClient component is a wrapper by tRPC around this functionality. This lead me to the next issue.
More on Issue 1 and 2
Initially, tried logging the prefetched queries in the dehydrate option within the createQueryClient function:
Again, I'm not sure if this intended, but I believe the query.state.dataUpdatedAt value being 0 could be the reason for the hydration cancellation. I tried the following changes.
export const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 0,
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
// initialDataUpdatedAt: Date.now(), // <----- Doesn't seem to work,
// Returns 0 for each query prefetched on a dev server
},
dehydrate: {
shouldDehydrateQuery: (query) => {
console.log(query.queryHash, "🔥 Before", query.state.dataUpdatedAt);
query.state.dataUpdatedAt = Date.now(); // <--------------A workaround for the above
console.log(query.queryHash, "🔥 After", query.state.dataUpdatedAt);
return (
defaultShouldDehydrateQuery(query) ||
query.state.status === "pending"
);
},
serializeData: transformer.serialize,
},
hydrate: {
deserializeData: transformer.deserialize,
},
},
});
This actually did hydrate into the client query-cache. But it triggered the Suspense fallback, a result similar to the gcTime:0 method.
Screen.Recording.2024-11-02.at.112.59.44.AM-1.mov
👨👧👦 Contributing
🙋♂️ Yes, I'd be down to file a PR fixing this bug!
Funding
You can sponsor this specific effort via a Polar.sh pledge below
We receive the pledge once the issue is completed & verified
The text was updated successfully, but these errors were encountered:
I’ve been thinking more about this issue, and it feels pretty framework specific. Not sure how much longer I’d like to keep this issue open. Whatever the outcome, I’d really appreciate some clarity on how prefetching, hydration, and suspense work together in this context + patterns and strategies to implement them effectively. If anyone has good resources on this, that’d be much appreciated. It’d really help me (and anybody interested) understand things better, not necessarily for contributing to the tRPC repo itself, but more for the framework example repos and documentation.
Provide environment information
System:
OS: macOS 14.1.1
CPU: (10) arm64 Apple M1 Pro
Memory: 59.63 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.10.0 - /usr/local/bin/node
Yarn: 1.22.21 - /usr/local/bin/yarn
npm: 10.2.3 - /usr/local/bin/npm
pnpm: 9.6.0 - /usr/local/bin/pnpm
bun: 1.0.21 - ~/.bun/bin/bun
Browsers:
Chrome: 130.0.6723.92
Safari: 17.1
npmPackages:
@tanstack/react-query: ^5.50.0 => 5.59.16
@trpc/client: ^11.0.0-rc.446 => 11.0.0-rc.608+f75de97b3
@trpc/react-query: ^11.0.0-rc.446 => 11.0.0-rc.608+f75de97b3
@trpc/server: ^11.0.0-rc.446 => 11.0.0-rc.608+f75de97b3
next: ^15.0.1 => 15.0.2
react: ^18.3.1 => 18.3.1
typescript: ^5.5.3 => 5.6.3
Describe the bug
Inconsistency in prefetch behaviour and query.state.dataUpdatedAt values between next versions
Note
I will be adding console logs on the server wherever needed
I will also be setting these query defaults to avoid any client side fetches
Redundant prefetches on pages with a prefetch next-15
Due to the changes to the client-side router with latest Next-15 update, pages that had a prefetch in them, re-run on every page request resulting in a bunch of redundant prefetches running on the server and none of the subsequent queries hydrating the client query cache.
382367362-1ba71558-fecc-435d-a93d-08ff44959242.mov
Inconsistency with the query.state.dataUpdatedAt value
I'm unaware of the true implications that this could have but I found this out while debugging the first issue. The query.state.dataUpdatedAt values are inconsistent across versions and environments.
Dev server: Next 14.2.16 vs Next 15.0.2:
Prod server: Next 14.2.16 vs Next 15.0.2:
Link to reproduction
https://github.com/MlNl-PEKKA/trpc-test
To reproduce
Replication of Issue 1 :
This issue can be reproduced by trying out the rsc-rq-prefetch demo in the trpc/examples-next-app-dir repository which was upgraded to Next-15, two days ago.
Replication of Issue 2 :
Additional information
More on Issue 1
I am not sure if the subsequent prefetches on navigation are meant to be sent down to the front-end, or even be triggered again in the first place.
Although, I think this new behaviour could be helpful if the prefetched query is sent down and hydrated in the front-end. Which lead me down a path to get this behaviour to work. My initial plan was to the set the default garbage collection time to 0, leading to queries being removed from the cache when there aren't any observers left. This did yield the result and the prefetched queries were successfully hydrating into the client query cache. But this resulted in a horrendous fallback UI to appear on every navigation.
Eventually, I had a look around in react-query docs regarding hydration and came across this limitation regarding hydration. Please correct if I'm wrong. I'm assuming that the HydrateClient component is a wrapper by tRPC around this functionality. This lead me to the next issue.
More on Issue 1 and 2
Initially, tried logging the prefetched queries in the dehydrate option within the createQueryClient function:
Again, I'm not sure if this intended, but I believe the query.state.dataUpdatedAt value being 0 could be the reason for the hydration cancellation. I tried the following changes.
This actually did hydrate into the client query-cache. But it triggered the Suspense fallback, a result similar to the gcTime:0 method.
Screen.Recording.2024-11-02.at.112.59.44.AM-1.mov
👨👧👦 Contributing
Funding
The text was updated successfully, but these errors were encountered: