T
TanStack•10mo ago
foreign-sapphire

useInfiniteQuery with more than 1 param

hy, im trying to create infinite scroll with the useinfinitequery, my issue that it only accept 1 param which is the pageParam, how can i make it accept other params like sort and filter
import { useInfiniteQuery } from '@tanstack/react-query';
import { useSearchParams } from 'react-router-dom';

export const useInifiniteData3 = () => {
const [searchParam, setSearchParam] = useSearchParams();
const page = searchParam.get('page') * 1 || 1;
const limit = searchParam.get('limit') * 1 || 10;

const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['datas'],
// queryFn: (obj) => fetchDatas3(obj),
// queryFn: () => fetchDatas3({ pageParam: page, limitParam: limit }),
queryFn: fetchDatas3,
initialPageParam: page, // initial pageParam = 1

getNextPageParam: (lastPage, allPages) => {
const nextPage = lastPage?.hasNextPage ? allPages.length + 1 : undefined;
return nextPage;
// const obj = { pageParam: nextPage, limitParam: limit };
// return obj;
},
});
return { data, isLoading, fetchNextPage, hasNextPage };
};

const fetchDatas3 = async ({ pageParam = 1, limitParam = 10 }) => {
console.log('function', pageParam, limitParam);
const res = await fetch(
`http://localhost:5000/data/datas?page=${pageParam}&limit=${limitParam}`
);

const data = await res.json();

return data;
// output:
// {
// data: [],
// totolItems: 100,
// hasNextPage: true,
// }
};
import { useInfiniteQuery } from '@tanstack/react-query';
import { useSearchParams } from 'react-router-dom';

export const useInifiniteData3 = () => {
const [searchParam, setSearchParam] = useSearchParams();
const page = searchParam.get('page') * 1 || 1;
const limit = searchParam.get('limit') * 1 || 10;

const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['datas'],
// queryFn: (obj) => fetchDatas3(obj),
// queryFn: () => fetchDatas3({ pageParam: page, limitParam: limit }),
queryFn: fetchDatas3,
initialPageParam: page, // initial pageParam = 1

getNextPageParam: (lastPage, allPages) => {
const nextPage = lastPage?.hasNextPage ? allPages.length + 1 : undefined;
return nextPage;
// const obj = { pageParam: nextPage, limitParam: limit };
// return obj;
},
});
return { data, isLoading, fetchNextPage, hasNextPage };
};

const fetchDatas3 = async ({ pageParam = 1, limitParam = 10 }) => {
console.log('function', pageParam, limitParam);
const res = await fetch(
`http://localhost:5000/data/datas?page=${pageParam}&limit=${limitParam}`
);

const data = await res.json();

return data;
// output:
// {
// data: [],
// totolItems: 100,
// hasNextPage: true,
// }
};
in my component i have sort and limit button to create params in the url
limit=10&sort=firstName
limit=10&sort=firstName
and in the getNextParams it return a 1 value, so does anyone know how to do it, if possible. thank you
12 Replies
ambitious-aqua
ambitious-aqua•10mo ago
Put limitParam in the queryKey and then you can do:
queryKey: ['data', limitParam],
queryFn: async ({ pageParam }) => {
const res = await fetch(`BASE_URL_HERE/data/datas?page=${pageParam}&limit=${limitParam}`
}
queryKey: ['data', limitParam],
queryFn: async ({ pageParam }) => {
const res = await fetch(`BASE_URL_HERE/data/datas?page=${pageParam}&limit=${limitParam}`
}
I've missed the json in that queryFn but that should make sense
ambitious-aqua
ambitious-aqua•10mo ago
Since your using React Router I'm gonna leave this here https://tkdodo.eu/blog/react-query-meets-react-router (You could also consider Tanstack Router if the migration wouldn't be too painful 🙂)
React Query meets React Router
React Query and React Router are a match made in heaven.
foreign-sapphire
foreign-sapphireOP•10mo ago
still not working😅 but im gonna look into the blog for anything could help
ambitious-aqua
ambitious-aqua•10mo ago
The whole series is a must read to be fair Also put the sort param in the key and fn as well
ambitious-aqua
ambitious-aqua•10mo ago
This is probably very useful as well https://tkdodo.eu/blog/the-query-options-api
The Query Options API
v5 brought a new, powerful API, especially if you're using React Query with TypeScript...
foreign-sapphire
foreign-sapphireOP•10mo ago
ive reach place that it's working but the 1st array is read twice, the first time, then when i do fetchNext, i read the same data then it works normal, so if i have ten page i end up at 11 and crash, im trying in the getNextPageParam to read the last response and make logic to calculate the next page which is correct but only for the first time it's wrong yeah i did that yeah ive read the docs of infiniteQuery and the example they provide on their site all check this as well
ambitious-aqua
ambitious-aqua•10mo ago
Can you make the backend api return a cursor?
foreign-sapphire
foreign-sapphireOP•10mo ago
u mean like this?
No description
foreign-sapphire
foreign-sapphireOP•10mo ago
the hasNextPage and nextPage are basically the same because in the getNextPageParam i do this:
return lastPage.hasNextPage ? allPages.length + 1 : undefined;
// return lastPage.hasNextPage ? lastPage.nextPage : undefined;
return lastPage.hasNextPage ? allPages.length + 1 : undefined;
// return lastPage.hasNextPage ? lastPage.nextPage : undefined;
ambitious-aqua
ambitious-aqua•10mo ago
Drizzle ORM - SQL Cursor-based pagination
Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.
Pagination (Reference) | Prisma Documentation
Prisma Client supports both offset pagination and cursor-based pagination. Learn more about the pros and cons of different pagination approaches and how to implement them.
ambitious-aqua
ambitious-aqua•10mo ago
Also if you own your own backend, I'd heavly recommend tRPC
foreign-sapphire
foreign-sapphireOP•10mo ago
i believe my backend implementation is correct i test the api for all case and they work correct:
const getDatas = async (req, res) => {
try {
const sort = req.query.sort;
const page = req.query.page * 1 || 1;
const limit = req.query.limit * 1 || 10;
const skip = (page - 1) * limit;
// example if im in page 2, limit = 10:
// skip = (2 - 1) * 10 = 10; start at index 11
// so the first element of page 2 will the 11th item

const totalItems = await Data.countDocuments(); // arr.length
let query;
if (sort) {
query = await Data.find().sort(sort).skip(skip).limit(limit);
} else {
query = await Data.find().skip(skip).limit(limit);
}

const hasNextPage = totalItems - page * limit > 0;

res.json({
data: query,
hasNextPage,
nextPage: hasNextPage ? page + 1 : null,
totalItems,
});
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server Error' });
}
};
const getDatas = async (req, res) => {
try {
const sort = req.query.sort;
const page = req.query.page * 1 || 1;
const limit = req.query.limit * 1 || 10;
const skip = (page - 1) * limit;
// example if im in page 2, limit = 10:
// skip = (2 - 1) * 10 = 10; start at index 11
// so the first element of page 2 will the 11th item

const totalItems = await Data.countDocuments(); // arr.length
let query;
if (sort) {
query = await Data.find().sort(sort).skip(skip).limit(limit);
} else {
query = await Data.find().skip(skip).limit(limit);
}

const hasNextPage = totalItems - page * limit > 0;

res.json({
data: query,
hasNextPage,
nextPage: hasNextPage ? page + 1 : null,
totalItems,
});
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server Error' });
}
};
even in the front end they work fine, but the 1st time i call fetchNextPage i got the 1st array of data again so i end up in page 11 instead of 10 if there's 100 items where limit is 10

Did you find this page helpful?