Hvordan implementere uendelig rulling og paginering med Next.js og TanStack Query

De fleste apper du vil utvikle vil administrere data; etter hvert som programmene fortsetter å skalere, kan det bli en stadig større mengde av det. Når applikasjoner ikke klarer å administrere store datamengder effektivt, gir de dårlige resultater.

Paginering og uendelig rulling er to populære teknikker du kan bruke for å optimalisere appytelsen. De kan hjelpe deg med å håndtere datagjengivelse mer effektivt og forbedre den generelle brukeropplevelsen.

Paginering og uendelig rulling ved hjelp av TanStack Query

TanStack-spørring—en tilpasning av React Query — er et robust tilstandsadministrasjonsbibliotek for JavaScript-applikasjoner. Den tilbyr en effektiv løsning for å administrere applikasjonstilstand, blant andre funksjoner, inkludert datarelaterte oppgaver som hurtigbufring.

Paginering innebærer å dele et stort datasett i mindre sider, slik at brukerne kan navigere innholdet i håndterbare deler ved hjelp av navigasjonsknapper. I kontrast gir uendelig rulling en mer dynamisk nettleseropplevelse. Når brukeren ruller, lastes og vises nye data automatisk, noe som eliminerer behovet for eksplisitt navigering.

Paginering og uendelig rulling har som mål å effektivt administrere og presentere store datamengder. Valget mellom de to avhenger av applikasjonens datakrav.

Du finner dette prosjektets kode i denne GitHub oppbevaringssted.

Sette opp et Next.js-prosjekt

For å komme i gang, lag et Next.js-prosjekt. Installer den nyeste versjonen av Next.js 13 som bruker appkatalogen.

 npx create-next-app@latest next-project --app 

Installer deretter TanStack-pakken i prosjektet ditt ved å bruke npm, Node-pakkebehandleren.

 npm i @tanstack/react-query 

Integrer TanStack Query i Next.js-applikasjonen

For å integrere TanStack Query i Next.js-prosjektet ditt, må du opprette og initialisere en ny forekomst av TanStack Query i roten av applikasjonen – layout.js-filen. For å gjøre det, importer QueryClient og QueryClientProvider fra TanStack Query. Pakk deretter inn barnerekvisitten 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.

  Topp 11 Apple Watch-spill for å ha det gøy rett på håndleddet

UseQuery-kroken effektiviserer henting og administrasjon av data. Ved å oppgi pagineringsparametere, for eksempel sidetall, kan du enkelt hente spesifikke delsett av data.

I tillegg gir kroken ulike alternativer og konfigurasjoner for å tilpasse datahentingsfunksjonaliteten din, inkludert innstilling av hurtigbufferalternativer, samt håndtering av lastetilstander effektivt. Med disse funksjonene kan du enkelt lage en sømløs pagineringsopplevelse.

Nå, for å implementere paginering i Next.js-appen, lag en paginering/page.js-fil i src/app-katalogen. Inne i denne filen gjør du følgende importer:

 "use client"
import React, { useState } from 'react';
import { useQuery} from '@tanstack/react-query';
import './page.styles.css';

Definer deretter en React funksjonell komponent. Inne i denne komponenten må du definere en funksjon som skal hente data fra en ekstern API. I dette tilfellet, bruk JSONPlaceholder API for å hente et sett 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-kroken, og spesifiser følgende parametere som objekter:

   const { isLoading, isError, error, data } = useQuery({
    keepPreviousData: true,
    queryKey: ['posts', page],
    queryFn: fetchPosts,
  });

KeepPreviousData-verdien er true, noe som sikrer at appen bevarer de tidligere dataene mens den henter nye data. queryKey-parameteren er en matrise som inneholder nøkkelen for spørringen, i dette tilfellet endepunktet og den gjeldende siden du vil hente data for. Til slutt utløser queryFn-parameteren, fetchPosts, funksjonskallet for å hente data.

Som nevnt tidligere, gir kroken flere tilstander som du kan pakke ut, lik hvordan du ville destrukturert arrays og objekter, og utnyttet dem til å forbedre brukeropplevelsen (gjengi passende brukergrensesnitt) under datahentingsprosessen. Disse tilstandene inkluderer isLoading, isError og mer.

For å gjøre det, ta med følgende kode for å gjengi forskjellige meldingsskjermer basert på den nåværende tilstanden til den pågående prosessen:

   if (isLoading) {
    return (<h2>Loading...</h2>);
  }

  if (isError) {
    return (<h2 className="error-message">{error.message}</h2>);
  }

Til slutt inkluderer du koden for JSX-elementene som skal gjengis på nettlesersiden. Denne koden har også to andre funksjoner:

  • Når appen henter innleggene fra API-en, vil de bli lagret i datavariabelen levert av useQuery-kroken. Denne variabelen hjelper til med å administrere applikasjonens tilstand. Du kan deretter kartlegge listen over innlegg som er lagret i denne variabelen, og gjengi dem i nettleseren.
  • For å legge til to navigasjonsknapper, Forrige og Neste, for å tillate brukere å spørre og vise ytterligere paginerte data tilsvarende.
   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>
  );

Til slutt, start utviklingsserveren.

 npm run dev 

Gå deretter over til http://localhost:3000/Pagination i en nettleser.

  Beste måter å vise NFT-er i hjemmet ditt

Siden du inkluderte pagineringsmappen i appkatalogen, behandler Next.js den som en rute, slik at du får tilgang til siden på den nettadressen.

Uendelig rulling gir en sømløs nettleseropplevelse. Et godt eksempel er YouTube, som henter nye videoer automatisk og viser dem mens du ruller nedover.

UseInfiniteQuery-kroken lar deg implementere uendelig rulling ved å hente data fra en server på sider og automatisk hente og gjengi neste side med data når brukeren ruller nedover.

For å implementere uendelig rulling, legg til en InfiniteScroll/page.js-fil i src/app-katalogen. Foreta deretter følgende importer:

 "use client"
import React, { useRef, useEffect, useState } from 'react';
import { useInfiniteQuery } from '@tanstack/react-query';
import './page.styles.css';

Deretter oppretter du en React-funksjonell komponent. Inne i denne komponenten, lik pagineringsimplementeringen, lag en funksjon som vil hente postenes data.

 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 pagineringsimplementeringen, introduserer denne koden en to-sekunders forsinkelse ved henting av data for å la en bruker utforske gjeldende data mens de ruller for å utløse en gjenhenting av et nytt sett med data.

  De 10 kuleste påskeeggene i Tesla EVs

Definer nå useInfiniteQuery-kroken. Når komponenten først monteres, vil kroken hente den første siden med data fra serveren. Når brukeren ruller nedover, henter kroken automatisk neste side med data og gjengir 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 flatet versjon av datavariabelen. Dette lar deg enkelt kartlegge og gjengi de enkelte innleggene.

For å spore brukerrulling 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 visningsporten.

   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 inkluderer JSX-elementene for innleggene som gjengis 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 dem i aksjon.

TanStack Query: Mer enn bare datahenting

Paginering og uendelig rulling er gode eksempler som fremhever mulighetene til TanStack Query. Enkelt sagt, det er et allsidig databehandlingsbibliotek.

Med det omfattende sett med funksjoner kan du strømlinjeforme appens databehandlingsprosesser, inkludert effektiv håndtering av staten. Ved siden av andre datarelaterte oppgaver kan du forbedre den generelle ytelsen til nettapplikasjonene dine, så vel som brukeropplevelsen.