Većina aplikacija koje razvijate upravljaće podacima; kako programi rastu, količina podataka može eksponencijalno da se poveća. Ako aplikacije ne uspeju da efikasno upravljaju velikim količinama podataka, njihove performanse će biti loše.
Paginacija i beskonačno skrolovanje su dve popularne tehnike koje možete primeniti radi optimizacije performansi vaše aplikacije. Ove tehnike vam pomažu da efikasnije rukovodite prikazom podataka i poboljšate celokupno korisničko iskustvo.
Paginacija i beskonačno skrolovanje uz TanStack Query
TanStack Query, adaptacija React Query-ja, predstavlja robusnu biblioteku za upravljanje stanjem u JavaScript aplikacijama. Ona nudi efikasno rešenje za upravljanje stanjem aplikacije, uključujući razne funkcionalnosti vezane za podatke kao što je keširanje.
Paginacija uključuje podelu velikog seta podataka na manje, numerisane stranice. To omogućava korisnicima da se kreću kroz sadržaj u manjim, preglednim delovima uz pomoć navigacionih dugmadi. Sa druge strane, beskonačno skrolovanje pruža dinamičnije iskustvo pregleda. Dok korisnik skroluje, novi podaci se automatski učitavaju i prikazuju, eliminišući potrebu za eksplicitnom navigacijom.
I paginacija i beskonačno skrolovanje imaju za cilj efikasno upravljanje i predstavljanje velikih količina podataka. Izbor između ove dve tehnike zavisi od specifičnih zahteva za podacima u vašoj aplikaciji.
Kompletan kod ovog projekta možete pronaći u GitHub repozitorijumu.
Podešavanje Next.js projekta
Za početak, kreirajte novi Next.js projekat. Preporučuje se da instalirate najnoviju verziju Next.js 13, koja koristi „App“ direktorijum.
npx create-next-app@latest next-project --app
Zatim, instalirajte TanStack paket u vaš projekat koristeći npm, Node Package Manager.
npm i @tanstack/react-query
Integracija TanStack Query-ja u Next.js aplikaciju
Da biste integrisali TanStack Query u vaš Next.js projekat, potrebno je da kreirate i inicijalizujete novu instancu TanStack Query-ja u korenu aplikacije – tačnije, u datoteci `layout.js`. Da biste to uradili, uvezite `QueryClient` i `QueryClientProvider` iz TanStack Query-ja. Zatim obmotajte `children` prop sa `QueryClientProvider` na sledeći način:
"use client" import React from 'react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query';const metadata = { title: 'Create Next App', description: 'Generated by create next app', };
export default function RootLayout({ children }) { const queryClient = new QueryClient();
return ( <html lang="en"> <body> <QueryClientProvider client={queryClient}> {children} </QueryClientProvider> </body> </html> ); }
export { metadata };
Ovo podešavanje osigurava da TanStack Query ima potpuni pristup stanju vaše aplikacije.
Hook `useQuery` pojednostavljuje proces dohvatana i upravljanja podacima. Prosleđivanjem parametara za paginaciju, kao što su brojevi stranica, možete lako preuzeti određene podskupove podataka.
Osim toga, hook pruža razne opcije i konfiguracije za prilagođavanje funkcionalnosti vašeg dohvatanja podataka, uključujući podešavanje opcija keširanja, kao i efikasno rukovanje stanjima učitavanja. Uz ove funkcije, možete bez napora kreirati besprekorno iskustvo paginacije.
Sada, da biste implementirali paginaciju u vašoj Next.js aplikaciji, kreirajte datoteku `Pagination/page.js` u `src/app` direktorijumu. U okviru ove datoteke dodajte sledeće uvoze:
"use client" import React, { useState } from 'react'; import { useQuery} from '@tanstack/react-query'; import './page.styles.css';
Zatim, definišite React funkcionalnu komponentu. U okviru ove komponente, potrebno je definisati funkciju koja će preuzimati podatke sa spoljnog API-ja. U ovom slučaju, koristićemo JSONPlaceholder API za preuzimanje skupa objava.
export default function Pagination() { const [page, setPage] = useState(1);const fetchPosts = async () => { try { const response = await fetch(`https://jsonplaceholder.typicode.com/posts? _page=${page}&_limit=10`);
if (!response.ok) { throw new Error('Failed to fetch posts'); }
const data = await response.json(); return data; } catch (error) { console.error(error); throw error; } };
}
Sada, definišite `useQuery` hook i prosledite sledeće parametre kao objekte:
const { isLoading, isError, error, data } = useQuery({ keepPreviousData: true, queryKey: ['posts', page], queryFn: fetchPosts, });
Vrednost `keepPreviousData` je postavljena na `true`, što osigurava da dok se novi podaci učitavaju, aplikacija zadržava prethodne podatke. Parametar `queryKey` je niz koji sadrži ključ za upit, u ovom slučaju krajnju tačku i trenutnu stranicu za koju želite da preuzmete podatke. Na kraju, parametar `queryFn`, `fetchPosts`, pokreće poziv funkcije za preuzimanje podataka.
Kao što je ranije pomenuto, hook pruža nekoliko stanja koja možete raspakovati, slično kao što biste destruktuirali nizove i objekte, i iskoristiti ih za poboljšanje korisničkog iskustva (renderovanje odgovarajućih korisničkih interfejsa) tokom procesa preuzimanja podataka. Ova stanja uključuju `isLoading`, `isError`, i mnoga druga.
Da biste to uradili, uključite sledeći kod da prikažete različite ekrane poruka u zavisnosti od trenutnog stanja procesa u toku:
if (isLoading) { return (<h2>Loading...</h2>); }if (isError) { return (<h2 className="error-message">{error.message}</h2>); }
Na kraju, uključite kod za JSX elemente koji će se prikazati na stranici pretraživača. Ovaj kod takođe služi dve dodatne funkcije:
- Kada aplikacija preuzme objave sa API-ja, one će biti uskladištene u varijabli `data` koju obezbeđuje `useQuery` hook. Ova varijabla pomaže u upravljanju stanjem aplikacije. Zatim možete mapirati listu objava sačuvanih u ovoj varijabli i prikazati ih u pretraživaču.
- Da biste dodali dva navigaciona dugmeta, „Prethodna“ i „Sledeća“, koja omogućavaju korisnicima da šalju upite i shodno tome prikažu dodatne podatke sa stranica.
return ( <div> <h2 className="header">Next.js Pagination</h2> {data && ( <div className="card"> <ul className="post-list"> {data.map((post) => ( <li key={post.id} className="post-item">{post.title}</li> ))} </ul> </div> )} <div className="btn-container"> <button onClick={() => setPage(prevState => Math.max(prevState - 1, 0))} disabled={page === 1} className="prev-button" >Prev Page</button><button onClick={() => setPage(prevState => prevState + 1)} className="next-button" >Next Page</button> </div> </div> );
Na kraju, pokrenite razvojni server.
npm run dev
Zatim, idite na `http://localhost:3000/Pagination` u vašem pretraživaču.
Budući da ste uključili fasciklu „Pagination“ u direktorijum aplikacije, Next.js je tretira kao rutu, omogućavajući vam da pristupite stranici na toj URL adresi.
Beskonačno skrolovanje pruža besprekorno iskustvo pregledanja. Dobar primer je YouTube, koji automatski preuzima nove video snimke i prikazuje ih dok skrolujete nadole.
`useInfiniteQuery` hook vam omogućava da implementirate beskonačno skrolovanje preuzimanjem podataka sa servera po stranicama i automatskim dohvatanjem i prikazivanjem sledeće stranice podataka dok korisnik skroluje nadole.
Da biste implementirali beskonačno skrolovanje, dodajte datoteku `InfiniteScroll/page.js` u `src/app` direktorijum. Zatim, izvršite sledeće uvoze:
"use client" import React, { useRef, useEffect, useState } from 'react'; import { useInfiniteQuery } from '@tanstack/react-query'; import './page.styles.css';
Zatim, kreirajte React funkcionalnu komponentu. Unutar ove komponente, slično implementaciji paginacije, kreirajte funkciju koja će dohvatiti podatke objava.
export default function InfiniteScroll() { const listRef = useRef(null); const [isLoadingMore, setIsLoadingMore] = useState(false);const fetchPosts = async ({ pageParam = 1 }) => { try { const response = await fetch(`https://jsonplaceholder.typicode.com/posts? _page=${pageParam}&_limit=5`);
if (!response.ok) { throw new Error('Failed to fetch posts'); }
const data = await response.json(); await new Promise((resolve) => setTimeout(resolve, 2000)); return data; } catch (error) { console.error(error); throw error; } };
}
Za razliku od implementacije paginacije, ovaj kod uvodi kašnjenje od dve sekunde prilikom preuzimanja podataka kako bi omogućio korisniku da istražuje trenutne podatke dok skroluje i pokreće ponovno preuzimanje novog seta podataka.
Sada definišite `useInfiniteQuery` hook. Kada se komponenta inicijalno montira, hook će preuzeti prvu stranicu podataka sa servera. Dok korisnik skroluje nadole, hook će automatski preuzeti sledeću stranicu podataka i prikazati je u komponenti.
const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteQuery({ queryKey: ['posts'], queryFn: fetchPosts, getNextPageParam: (lastPage, allPages) => { if (lastPage.length < 5) { return undefined; } return allPages.length + 1; }, });const posts = data ? data.pages.flatMap((page) => page) : [];
Promenljiva `posts` kombinuje sve objave sa različitih stranica u jedan niz, što rezultira spljoštenom verzijom promenljive `data`. Ovo vam omogućava lako mapiranje i prikazivanje pojedinačnih objava.
Da biste pratili skrolovanje korisnika i učitavali više podataka kada je korisnik blizu dna liste, možete definisati funkciju koja koristi Intersection Observer API da otkrije kada se elementi ukrštaju sa okvirom za prikaz.
const handleIntersection = (entries) => { if (entries[0].isIntersecting && hasNextPage && !isFetching && !isLoadingMore) { setIsLoadingMore(true); fetchNextPage(); } };useEffect(() => { const observer = new IntersectionObserver(handleIntersection, { threshold: 0.1 });
if (listRef.current) { observer.observe(listRef.current); }
return () => { if (listRef.current) { observer.unobserve(listRef.current); } }; }, [listRef, handleIntersection]);
useEffect(() => { if (!isFetching) { setIsLoadingMore(false); } }, [isFetching]);
Na kraju, uključite JSX elemente za objave koje se prikazuju u pretraživaču.
return ( <div> <h2 className="header">Infinite Scroll</h2> <ul ref={listRef} className="post-list"> {posts.map((post) => ( <li key={post.id} className="post-item"> {post.title} </li> ))} </ul> <div className="loading-indicator"> {isFetching ? 'Fetching...' : isLoadingMore ? 'Loading more...' : null} </div> </div> );
Kada izvršite sve izmene, posetite `http://localhost:3000/InfiniteScroll` da biste videli kako radi.
TanStack Query: Više od samog preuzimanja podataka
Paginacija i beskonačno skrolovanje su odlični primeri koji ističu mogućnosti TanStack Query-ja. Jednostavno rečeno, to je sveobuhvatna biblioteka za upravljanje podacima.
Sa svojim širokim spektrom funkcija, možete pojednostaviti procese upravljanja podacima u vašoj aplikaciji, uključujući efikasno rukovanje stanjem. Pored ostalih zadataka vezanih za podatke, možete poboljšati ukupne performanse vaših veb aplikacija, kao i korisničko iskustvo.