De fleste applikasjoner håndterer data, og datamengden kan øke betydelig etter hvert som applikasjonene vokser. Hvis applikasjoner ikke administrerer store datamengder på en effektiv måte, kan det føre til dårlig ytelse.
To vanlige metoder for å optimere applikasjonsytelsen er paginering og uendelig rulling. Disse teknikkene hjelper med å behandle datavisning mer effektivt og forbedrer brukeropplevelsen.
Paginering og uendelig rulling med TanStack Query
TanStack Query, en videreutvikling av React Query, er et robust bibliotek for tilstandshåndtering i JavaScript-applikasjoner. Det tilbyr en effektiv løsning for å håndtere applikasjonstilstand, inkludert datahåndtering og hurtigbufring.
Paginering deler store datasett inn i mindre sider, slik at brukerne kan navigere gjennom innholdet i håndterbare deler ved hjelp av navigasjonsknapper. Uendelig rulling gir derimot en mer dynamisk nettleseropplevelse der nye data lastes og vises automatisk når brukeren ruller, uten at det er nødvendig med eksplisitt navigering.
Både paginering og uendelig rulling har som mål å effektivt håndtere og presentere store mengder data. Valget mellom dem avhenger av applikasjonens spesifikke behov.
Koden for dette prosjektet er tilgjengelig på dette GitHub-repositoriet.
Oppsett av et Next.js-prosjekt
For å begynne, opprett et nytt Next.js-prosjekt. Installer den nyeste versjonen av Next.js 13 som benytter app-katalogen.
npx create-next-app@latest next-project --app
Installer deretter TanStack-pakken i prosjektet ved hjelp av npm, Node Package Manager.
npm i @tanstack/react-query
Integrer TanStack Query i Next.js-applikasjonen
For å integrere TanStack Query i Next.js-prosjektet, må du opprette og initialisere en ny forekomst av TanStack Query i rotfilen for applikasjonen, layout.js. Importér QueryClient og QueryClientProvider fra TanStack Query. Deretter omslutter du barn-elementet med QueryClientProvider som følger:
"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 };
Dette oppsettet sikrer at TanStack Query har full tilgang til applikasjonens tilstand.
UseQuery-hooken forenkler henting og håndtering av data. Ved å spesifisere pagineringsparametre, som for eksempel sidetall, kan du enkelt hente spesifikke delsett av data.
I tillegg tilbyr hooken ulike alternativer og konfigurasjoner for å tilpasse datahentingsfunksjonaliteten, inkludert å sette hurtigbufringsalternativer og håndtere lastetilstander effektivt. Med disse funksjonene kan du enkelt skape en sømløs pagineringsopplevelse.
For å implementere paginering i Next.js-appen, opprett en fil kalt pagination/page.js i src/app-katalogen. I denne filen legger du inn følgende importer:
"use client" import React, { useState } from 'react'; import { useQuery} from '@tanstack/react-query'; import './page.styles.css';
Deretter definerer du en React funksjonell komponent. Inne i denne komponenten definerer du en funksjon for å hente data fra et eksternt API. Her bruker vi JSONPlaceholder API for å hente en samling med innlegg.
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; } }; }
Definer nå useQuery-hooken og spesifiser følgende parametere som objekter:
const { isLoading, isError, error, data } = useQuery({ keepPreviousData: true, queryKey: ['posts', page], queryFn: fetchPosts, });
KeepPreviousData-verdien er satt til true, noe som sikrer at appen beholder de tidligere dataene mens den laster inn nye data. queryKey-parameteren er en matrise som inneholder nøkkelen for forespørselen, i dette tilfellet endepunktet og gjeldende side for dataene du vil hente. Til slutt utløser queryFn-parameteren funksjonen fetchPosts for å hente data.
Som tidligere nevnt gir hooken flere tilstander som du kan trekke ut, på samme måte som du ville destrukturert arrays og objekter, for å forbedre brukeropplevelsen (gjengi relevante brukergrensesnitt) under datahentingsprosessen. Disse tilstandene inkluderer isLoading, isError og mer.
For å gjøre det, inkluder følgende kode for å gjengi forskjellige meldinger avhengig av den gjeldende tilstanden i den pågående prosessen:
if (isLoading) { return (<h2>Loading...</h2>); } if (isError) { return (<h2 className="error-message">{error.message}</h2>); }
Til slutt legger du til koden for JSX-elementene som skal vises på nettlesersiden. Denne koden har også to andre funksjoner:
- Når appen henter innleggene fra API-et, vil de lagres i datavariabelen som er gitt av useQuery-hooken. Denne variabelen hjelper deg med å administrere applikasjonens tilstand. Deretter kan du vise listen over innlegg som er lagret i denne variabelen, i nettleseren.
- For å legge til to navigasjonsknapper, Forrige og Neste, slik at brukerne kan forespørre og vise flere paginerte data.
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> );
Start til slutt utviklingsserveren.
npm run dev
Gå deretter til http://localhost:3000/Pagination i en nettleser.
Siden du inkluderte pagineringsmappen i app-katalogen, behandler Next.js den som en rute, slik at du får tilgang til siden på den nettadressen.
Uendelig rulling gir en mer sømløs nettleseropplevelse. Et godt eksempel er YouTube, som laster inn nye videoer automatisk når du ruller nedover.
UseInfiniteQuery-hooken lar deg implementere uendelig rulling ved å hente data fra en server i sider og automatisk hente og vise den neste siden med data når brukeren ruller nedover.
For å implementere uendelig rulling, legg til en fil med navn InfiniteScroll/page.js i src/app-katalogen. Deretter importerer du følgende:
"use client" import React, { useRef, useEffect, useState } from 'react'; import { useInfiniteQuery } from '@tanstack/react-query'; import './page.styles.css';
Opprett deretter en React funksjonell komponent. I denne komponenten, på samme måte som ved paginering, oppretter du en funksjon for å hente postdata.
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; } }; }
I motsetning til paginering, introduserer denne koden en tosekunders forsinkelse ved henting av data for å la brukeren utforske gjeldende data mens de ruller og utløser henting av et nytt datasett.
Definer nå useInfiniteQuery-hooken. Når komponenten først monteres, vil hooken hente den første siden med data fra serveren. Når brukeren ruller nedover, henter hooken automatisk den neste siden med data og viser den i komponenten.
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) : [];
Posts-variabelen kombinerer alle innleggene fra forskjellige sider til en enkelt matrise, noe som resulterer i en flat versjon av datavariabelen. Dette gjør det enkelt å vise de enkelte innleggene.
For å spore brukerens rulling og laste inn mer data når brukeren er nær bunnen av listen, kan du definere en funksjon som bruker Intersection Observer API for å oppdage når elementer krysser synsfeltet.
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]);
Til slutt legger du til JSX-elementene for innleggene som skal vises i nettleseren.
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> );
Når du har gjort alle endringene, besøk http://localhost:3000/InfiniteScroll for å se hvordan det fungerer.
TanStack Query: Mer enn bare datahenting
Paginering og uendelig rulling er gode eksempler som viser mulighetene til TanStack Query. Kort sagt er det et allsidig bibliotek for datahåndtering.
Med det omfattende settet med funksjoner kan du strømlinjeforme appens datahåndteringsprosesser, inkludert effektiv håndtering av tilstanden. I tillegg til andre datarelaterte oppgaver kan du forbedre den generelle ytelsen til nettapplikasjonene dine og brukeropplevelsen.