T
TanStack•16mo ago
wee-brown

useInfiniteQuery: Trouble with refetching when moving between routes (nextjs)

Hey, i've been stuck for days on this: I use searchParams to show filtered posts. When I switch routes from the browse page in this state: /browse?filter=production and then come back by clicking browse Link in Navbar the results remain the same, although can confirm that the initialData gets updated. It should be the data without any filters because there is no searchparams... This is useInfiniteQuery hook from my app. the initialData is fetched on the server
// v5 tanstack/react-query
const { data, fetchNextPage, isFetchingNextPage, hasNextPage } =
useInfiniteQuery({
queryKey: ['infinite'],
queryFn: ({ pageParam = {} }): Promise<TQueryFnData> => {
return fetchPostsFromSanity(pageParam)
},
getNextPageParam: (lastPage) => {
if (
lastPage &&
lastPage.length > 0 &&
lastPage.length === numberOfItemsPerPage
) {
const lastPost = lastPage[lastPage.length - 1]

return {
lastPublishedAt: lastPost.publishedAt!,
lastId: lastPost._id
}
}
return undefined // Indicates there are no more pages to load
},
initialData: {
pages: [initialPosts],
pageParams: [{}]
},
initialPageParam: {}
})
// v5 tanstack/react-query
const { data, fetchNextPage, isFetchingNextPage, hasNextPage } =
useInfiniteQuery({
queryKey: ['infinite'],
queryFn: ({ pageParam = {} }): Promise<TQueryFnData> => {
return fetchPostsFromSanity(pageParam)
},
getNextPageParam: (lastPage) => {
if (
lastPage &&
lastPage.length > 0 &&
lastPage.length === numberOfItemsPerPage
) {
const lastPost = lastPage[lastPage.length - 1]

return {
lastPublishedAt: lastPost.publishedAt!,
lastId: lastPost._id
}
}
return undefined // Indicates there are no more pages to load
},
initialData: {
pages: [initialPosts],
pageParams: [{}]
},
initialPageParam: {}
})
I tried: queryClient.resetQueries() in useEffect() when initialData changes also queryClient.refetchQueries() but none of this refetches the data. the data.pages are not updated until i hard refresh the page.
7 Replies
xenial-black
xenial-black•16mo ago
initialData is only respected once, when the cache entry is created. That's why the hydration approach is usually preferred. With hydration, you'd always write the latest server data into the cache.
wee-brown
wee-brownOP•16mo ago
thanks @TkDodo 🔮 first time I hear about hydration. will try to find some info on this
xenial-black
xenial-black•16mo ago
Server Rendering & Hydration | TanStack Query React Docs
In this guide you'll learn how to use React Query with server rendering. See the guide on Prefetching & Router Integration for some background. You might also want to check out the Performance & Request Waterfalls guide before that.
wee-brown
wee-brownOP•16mo ago
hey again, uff it's hard! I'm trying to have a queryClient in my /browse/page.tsx to pass it to HydrationBoundry but it keeps returning empty object... am i doing something wrong?
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['infinite'],
queryFn: async () => {
const testFetch = await loadPosts()
const { data } = testFetch
if (data) {
return data
}
}
})
console.log('queryClient', queryClient)
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['infinite'],
queryFn: async () => {
const testFetch = await loadPosts()
const { data } = testFetch
if (data) {
return data
}
}
})
console.log('queryClient', queryClient)
xenial-black
xenial-black•16mo ago
your queryFn can return undefined if data is falsy, which isn't good the queryClient is a class so you likely can't just log that
wee-brown
wee-brownOP•16mo ago
you are right I tried without the initial data and with the hydration boundry, the queryClientProvider is in layout.
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['infinite'],
queryFn: () => {
const results = fetchPostsFromSanity({
lastPublishedAt: initialPublishedAt,
lastId: initialLastId
})
return results
}
})

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<BrowsePage data={initial.data} isDraftMode={false} results={results} />
</HydrationBoundary>
)
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['infinite'],
queryFn: () => {
const results = fetchPostsFromSanity({
lastPublishedAt: initialPublishedAt,
lastId: initialLastId
})
return results
}
})

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<BrowsePage data={initial.data} isDraftMode={false} results={results} />
</HydrationBoundary>
)
I believe this hydration boundry is not setting initial data because i see the posts loading for a bit. if i return null from queryFn functions it works the same as with all the fetching im doing on the server... The useInfiniteQuery:
const { data, fetchNextPage, isFetchingNextPage, hasNextPage } =
useInfiniteQuery({
queryKey: ['infinite'],
queryFn: ({ pageParam }) => {
const results = fetchPostsFromSanity(pageParam)
return results
},

getNextPageParam: (lastPage) => {
if (
lastPage &&
lastPage.length > 0 &&
lastPage.length === numberOfItemsPerPage
) {
const lastPost = lastPage[lastPage.length - 1]

return {
lastPublishedAt: lastPost.publishedAt!,
lastId: lastPost._id
}
}
return undefined // Indicates there are no more pages to load
},

initialPageParam: {
lastPublishedAt: initialPublishedAt,
lastId: initialLastId
}
})
const { data, fetchNextPage, isFetchingNextPage, hasNextPage } =
useInfiniteQuery({
queryKey: ['infinite'],
queryFn: ({ pageParam }) => {
const results = fetchPostsFromSanity(pageParam)
return results
},

getNextPageParam: (lastPage) => {
if (
lastPage &&
lastPage.length > 0 &&
lastPage.length === numberOfItemsPerPage
) {
const lastPost = lastPage[lastPage.length - 1]

return {
lastPublishedAt: lastPost.publishedAt!,
lastId: lastPost._id
}
}
return undefined // Indicates there are no more pages to load
},

initialPageParam: {
lastPublishedAt: initialPublishedAt,
lastId: initialLastId
}
})
I followed step by step the Advanced Server Rendering page. No idea. Cant get the initial data to render…
xenial-black
xenial-black•16mo ago
you can check the page source to see what gets sent down by next as hydrated data you can check the query devtools to see what gets put into the cache other than that - please try to reproduce it with codesandbox or stackblitz
const testFetch = await loadPosts()
const { data } = testFetch
if (data) {
return data
}
const testFetch = await loadPosts()
const { data } = testFetch
if (data) {
return data
}
do not return undefined from the queryFn. It's forbidden and won't work.

Did you find this page helpful?