Reputation: 1462
I tried to implement an infinite scroll with my react.js project using Infinite Queries in react-query and react-virtual. But Infinite query is supporting with the cursor and the page. and my API is not supported for pages, and it has a limit, offset, and totalCount in the metaData as below
meta: { limit: 100, offset: 0, total: 1000}
Are Infinite Queries support for limit and offset?
There are links that I followed.
https://codesandbox.io/s/github/tannerlinsley/react-virtual/tree/master/examples/infinite-scroll
https://react-query.tanstack.com/docs/guides/infinite-queries
Upvotes: 6
Views: 6892
Reputation: 1
Requesting Spotify API to fetch artist's album, with total, limit & offset.
import React, { useEffect, useState } from 'react';
import { useInfiniteQuery } from '@tanstack/react-query';
import { useInView } from 'react-intersection-observer';
import './App.css';
import { SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SEC } from './constants';
export default function App() {
const { ref, inView } = useInView();
const [count, setCount] = useState<number>(0);
const LIMIT = 10;
const getSpotifyAccessToken = async () => {
const encodedToken = btoa(`${SPOTIFY_CLIENT_ID}:${SPOTIFY_CLIENT_SEC}`);
const res = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
Authorization: `Basic ${encodedToken}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
}),
});
const data = await res.json();
// Sidhu: 4PULA4EFzYTrxYvOVlwpiQ
// Arijit: 4YRxDV8wJFPHPTeXepOstw
const response = await fetch(`https://api.spotify.com/v1/artists/4PULA4EFzYTrxYvOVlwpiQ/albums?album_type=SINGLE&offset=${count * LIMIT}&limit=${LIMIT}`, {
headers: {
Authorization: `Bearer ${data.access_token}`,
'Content-Type': 'application/x-www-form-urlencoded',
}
})
const finalData = await response.json()
return finalData as {
items: {
id: string;
name: string;
total: number;
images: {
height: number;
width: number;
url: string;
}[]
}[]
total: number;
};
}
const { data, isLoading, isError, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({
queryKey: ['items'],
queryFn: getSpotifyAccessToken,
initialPageParam: 0,
getNextPageParam: (lastPage) => Math.ceil(lastPage.total / LIMIT),
});
useEffect(() => {
if (inView) {
setCount((prev) => prev + 1);
}
}, [fetchNextPage, inView])
useEffect(() => { fetchNextPage() }, [count])
if (isLoading) {
return <div>Loading...</div>
}
if (isError) {
return <div>Error</div>
}
return (
<main style={{
display: "flex",
flexDirection: "column",
gap: "10px",
fontFamily: "cursive"
}}>
<h1 style={{
textAlign: "center"
}}>Sidhu Moosewala</h1>
{/* <h1 style={{
textAlign: "center"
}}>Arijit Singh</h1> */}
{data?.pages.map((page) => (
page.items.map((item) => (
<div style={{
display: "flex",
gap: "20px",
alignItems: "center",
padding: "10px",
backgroundColor: "green",
borderRadius: "8px",
cursor: "pointer"
}} key={item.id}
onClick={() => window.open(`https://open.spotify.com/album/${item.id}`, "_blank")}
>
<img
width={100}
height={100}
style={{
borderRadius: "5px"
}}
src={item.images[0].url}
/>
<h2 style={{
color: "white"
}}>{item.name}</h2>
</div>
))
))}
<div ref={ref}></div>
{isFetchingNextPage && <div>Loading...</div>}
<h2 style={{
textAlign: "center"
}}>You reached the boundary of infinite scroll, thanks for visiting us! (Sidhu, dil da ni maada..)</h2>
{/* Pyaar bhare gaane!! */}
</main>
)
}
Upvotes: 0
Reputation: 28988
infiniteQueries
don't really care how your backend delivers a "cursor" to the next page, it just matters that the backend delivers something.
Basically, whatever is returned from getNextPageParam
will be injected into the queryFn as pageParam
. Here is an example that might fit your use-case:
const { data } = useInfiniteQuery(
'key',
({ pageParam }) => axios.get(myUrl + '?offset=' + pageParam?.offset ?? 0),
{
getNextPageParam: (lastPage) => lastPage?.meta
}
)
The concept of a "page" is merely what ever your backend returns for a single fetch. So here, on the first fetch (for page 0), we have no pageParam, so we initalize with offset: 0
. Then, we fetch with that, and the backend returns the first set of data (a page), and we extract the meta info for it (offset = 20 or whatever).
If you call fetchNextPage()
, the queryFn will be called with that meta information, so the next fetch does ?offset=20
. The backend delivers offset: 40 as meta and the infinity continues.
Hope that explains it :)
Upvotes: 4