Question:
Making infinite scrolling using react-query

Problem:

I want to make infinite scroll for my project. Currently, I'm using Javascript fetching API but want to apply react-query instead of.


React query is a form of Hook so can't be nested inside of useCallback.


function RQInfiniteScrollTable({src}:{src:string}){

    const [page,setPage] = useState(1);

    const [pageData,setPageData]:[pageData:Array<object>,setPageData:any] = useState([]);


    const loadMore = useCallback(async () => {

        const new_page = page + 1;

        setPage(new_page);

        const buffer: Array<object> = [...pageData];

        let moreData:Response|null = await fetch([src,new_page].join("/").trim());

        let moreData_json:object|null = await moreData.json();

        if(moreData_json === null){return;}

        buffer.push(moreData_json);

        setPageData(buffer);

        return ()=>{moreData = null; moreData_json = null;};

    },[pageData]);


    const products:Array<React.ReactNode> = [];

    // @ts-ignore

    pageData.forEach(({title,image,price,category,description},index):void=>{

        products.push(

        <div key={index} className={"infinite-item-card"}>

            <div className={"w-full h-64 relative"}>

                <Image src={image} alt={title} layout={"fill"} objectPosition={"cover"} objectFit={"cover"}/>

            </div>

            <h1>{title}</h1>

            <p>{price}</p>

            <p>{category}</p>

            <p>{description}</p>

        </div>

        );

    });

    return(

    <div className={"w-full grid justify-items-center"}>

        <h1 className={"text-2xl w-fit my-8"}>{"Infinite Scroller"}</h1>

        <div className={"grid"}>{products}</div>

        <InfiniteScroller loadMore={loadMore}/> <-- this node callbacks given `loadMore` function when intersected.

    </div>

    );

}


How to solve this problem? I want to use react-query for better handling, with optimized way. and does query result of useQuery trigger re-render of the component?


Solution:

I'd suggest defining a query that takes the page number as a parameter, and then including that parameter in the query key. Then, whenever you update the page number, react-query will take care of automatically fetching the result. Here's a mock version I've sketched up:


useGetPaginatedDataQuery.tsx


export const useGetPaginatedDataQuery = (source: string, pageNumber: number) => {

  return useQuery(["paginatedData", pageNumber], {

    queryFn: async () => {

      const response = await fetch(`${source}/${pageNumber}`);

      return response.json();

    },

    enabled: !!pageNumber && pageNumber >= 0,

  }

}


RQInfiniteScrollTable.tsx


function RQInfiniteScrollTable({src}:{src:string}){

    const [page,setPage] = useState(1);

    const pageDataQuery = useGetPaginatedDataQuery(src, page);


    const loadMore = () => setPage((page) => page + 1);


    // The rest of your component



Suggested blogs:

>How to handle more than 100 cases neatly on Typescript?

>Type inference with 'as const' IN TypeScript

>Typescript Return argument: Tuple type or passed to rest parameter warning?

>How can you read a Blob in Deno in TypeScript?

>How to do Yup validation in form with TypeScript?

>How can I merge two arrays of objects that can be undefined in TypeScript?

>Javascript Error Solved: Property 'id' does not exist on type 'T'

>How to make sticky div remain stuck in JavaScript?

>How to manipulate manipulating Array object in JavaScript?



Ritu Singh

Ritu Singh

Submit
0 Answers