Published on 04/08/2025
I was dealing with pagination and useQuery. It seemed really simple at first, but then I ran in to some issues. I had my code set up exactly as shown in the examples. I was missing one key thing, that didnt come to mind at first...... what does the sever side code look like and act? I simply used the code for the hook, using page and limit in the search query param of the API route.
So I did the one thing developers hate doing lol RTFM(Reading the manual). It was very useful there was a lot of good info in there, what I learned is .... Rendering paginated data is a very common UI pattern and in TanStack Query, it "just works" by including the page information in the query key.
1const result = useQuery({
2 queryKey: ['projects', page],
3 queryFn: fetchProjects,
4})
What I read was that although this "just works" it is not optimal as it causes the UI to jump in and out of success and pending states because each page is treated like a new query. You can achieve better paginated queries with using placeholder data and setting it as keep previous data, This prevents the default behavior and The 'data from the last successful fetch is available while new data is being requested, even though the query key has changed'. This can simple be achieved with simple code:
1const { isPending, isError, error, data, isFetching, isPlaceholderData } =
2 useQuery({
3 queryKey: ['projects', page],
4 queryFn: () => fetchProjects(page),
5 placeholderData: keepPreviousData,
6 })
From the videos I have watched online one would think that it's as adding the search param page and limit. It wasn't lol!
1const fetchPastTrips = async ({ driverEmail, page }: { driverEmail: string, page: number }) => {
2 const response = await fetch(`/api/pastTrips/${driverEmail}?page=${page}&limit=${<limitValue>}`);
3 return await response.json();
4}
I wasted way more time then I would like to admit using old API routes and added search queries to the URL. I think admitting when you spent too much time on something simple is important. No one is great at everything, we've all had those moments where things have went way too smooth and you felt like a programming god, but at least for me those are not the norm and I think more people need to hear that.
At this point it was 11:00pm and I needed to get ready for bed, and as I was brushing my teeth it hit me like a brick wall. How could I not have seen it, what did everyone on youtube have in common that wasnt mentioned? The their backend must have been set up to handle the information in the search params, lol it's not some magic, I just missed it because it was so obvious no one had mentioned it. I forgot for a moment, in programming you have the tell the computer what to do, it doesnt just happen.
From there it was fairly simple, get the search params from the url and update the SQL. I know very funny using sql instead of an ORM, it's on my list of things to learn. So first lets get the value from the URL this is how I did it in NextJs:
I'll admit SQL is not my strong side and I am quick to use the LLM magic to achieve a quick out come. But that doesnt mean we can't also learn from what it produced. Let's go a head and look at the SQL I ended up going with:
1import { NextRequest, NextResponse } from 'next/server';
2
3export async function GET(request: NextRequest) {
4
5 const url = request.nextUrl;
6 const page = Number(url.searchParams.get('page')) || 1;
7 const limit = Number(url.searchParams.get('limit')) || 4;
LIMIT and OFFSET are SQL tools that help control how much data is shown at a time. LIMIT sets the number of items to show, like 10 or 20, and OFFSET decides where to start showing them, like starting from the first item or the 11th item. This helps with pagination, making it easier to navigate through large amounts of data by breaking it down into smaller, more manageable chunks.
1const offset = (page - 1) * limit;
2const result = await sql`
3 SELECT *
4 FROM PTTrips
5 WHERE driverEmail = ${uriDecodedDriverEmail}
6 ORDER BY date DESC
7 LIMIT ${limit}
8 OFFSET ${offset}`;
Even if you read the documentation and watch videos, if it seems like magic, it's because there's a gap in your understanding. With patience and persistence, you can bridge this gap and develop a deeper understanding of the subject. Keep an open mind, ask questions, and seek out additional resources until the concepts click into place
words