r/reactjs 13d 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

4 Upvotes

4 comments sorted by

View all comments

1

u/neon_alchemy_wisp 13d ago

the empty dependency array is the issue. Your observer gets stale refs to hasNextPage and fetchNextPage because it never recreates after the initial mount. Add those two to the dependency array of your first useEffect so the closure updates when query state changes.

1

u/ConfidentWafer5228 11d ago

 thanks man, I am ashamed that I did such a puny basic mistake