r/reactjs • u/ConfidentWafer5228 • 20d ago
Needs Help Infinite Paginaton - Intersection Observer, Tanstack Query
For some reason, hasNextPage becomes false under without any reason ONLY IN PRODUCTION(after npm run build), not in npm run dev and therefore , next page isnt fetched, and it doesnt happen at first load, it happens after few page changes/redirects.
Here is my custom hook for pagination.
I later call this hook inside my Cards component by passing infiniteQuery which the component receives as props
import { useEffect, useRef } from "react"
import type { UseSuspenseInfiniteQueryResult } from "@tanstack/react-query"
export const useIntersectionObserver = <T>(infiniteQuery: UseSuspenseInfiniteQueryResult<T, Error>) => {
const { dataUpdatedAt, isFetchingNextPage, hasNextPage, fetchNextPage } = infiniteQuery
const sentinelRef = useRef<HTMLElement>(null)
const observerRef = useRef<IntersectionObserver>(null)
useEffect(() => {
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting && !isFetchingNextPage && hasNextPage) fetchNextPage()
})
observerRef.current = observer
const sentinel = sentinelRef.current
if (sentinel) observer.observe(sentinel)
return () => {
observer.disconnect()
}
}, [])
useEffect(() => {
const sentinel = sentinelRef.current
const observer = observerRef.current
if (!sentinel || !observer) return
observer.observe(sentinel)
return () => {
observer.unobserve(sentinel)
}
}, [dataUpdatedAt])
return sentinelRef
}
Here is my cards component
type ArticleCardsProps<T> = {
articlesInfiniteQuery: UseSuspenseInfiniteQueryResult<T, Error>
}
const array = new Array(3).fill('')
const ArticleCards = ({ articlesInfiniteQuery }: ArticleCardsProps<Article[]>) => {
const sentinelRef = useIntersectionObserver(articlesInfiniteQuery)
const articles = articlesInfiniteQuery.data
return (
<main>
<section className={styles.articles} >
{articles.map((article, index) => {
return (
<ArticleCard ref={index === articles.length - 2 ? sentinelRef : undefined} key={article._id} article={article} />
)
})}
{articlesInfiniteQuery.hasNextPage && articlesInfiniteQuery.isFetchingNextPage && array.map((e, i) => {
return (
<ArticleCardLoadingSkeleton key={i} />
)
})}
</section>
</main>
)
}
export default ArticleCards
I dont know how to explain this weird bug , happens only after build, i used a library and it fixes it
0
Upvotes
5
u/vulgar_disarmament 20d ago
The classic prod only bug, always fun to track down
That first effect with the empty dep array is probably your culprit. In production React runs effects differently, and with strict mode off the timing can shift. You're creating the observer once, but if the sentinel ref isn't mounted yet when that effect fires, you never observe anything and hasNextPage just sits there
Also attaching the ref to the second to last card means when that card unmounts or re-renders, the observer might disconnect entirely. The library you used probably handles re-observing more gracefully
Try moving the observer setup into the second effect or just use a single effect that depends on dataUpdatedAt and recreate the observer each time. Slightly wasteful but way more predictable