Oneindig scrollen en pagineren implementeren met Next.js en TanStack Query
De meeste apps die je ontwikkelt, zullen gegevens beheren; naarmate programma’s verder opschalen, kan er een steeds grotere hoeveelheid gegevens zijn. Als applicaties er niet in slagen om grote hoeveelheden gegevens effectief te beheren, presteren ze slecht.
Het gebruik van paginering en oneindig scrollen zijn praktische methoden om de efficiÃ"ntie van applicaties te optimaliseren, waardoor gegevens beter kunnen worden verwerkt en tegelijkertijd de algehele gebruikerservaring wordt verbeterd.
Pagineren en oneindig scrollen met behulp van TanStack Query
TanStack Query â€" een aanpassing van React Query â€" is een robuuste toestandsbeheerbibliotheek voor JavaScript-toepassingen. Het biedt een efficiÃ"nte oplossing voor het beheren van applicatietoestanden, naast andere functionaliteiten, waaronder gegevensgerelateerde taken zoals caching.
Pagineren is een methode om grote datasets te organiseren door ze op te splitsen in kleinere, gemakkelijk navigeerbare secties met behulp van paginering. Aan de andere kant biedt oneindig scrollen een adaptieve manier van browsen waarbij, wanneer de gebruiker naar beneden scrollt, aanvullende informatie wordt geladen en naadloos wordt weergegeven, waardoor directe navigatie overbodig wordt.
Pagineren en oneindig scrollen zijn beide methoden om grote hoeveelheden informatie op een gebruiksvriendelijke manier te beheren en weer te geven, elk met hun eigen voor- en nadelen afhankelijk van de specifieke behoeften van een toepassing.
Je kunt de broncode voor dit project vinden in de GitHub repository die ervoor is aangewezen.
Een Next.js project opzetten
Om het proces te starten, zet je een Next.js project op door de meest recente versie te installeren, versie 13, die gebruik maakt van een “App” map als basis.
npx create-next-app@latest next-project --app
Om verder te gaan, moet je het TanStack-pakket binnen je project installeren met behulp van npm, een veelgebruikte pakketbeheerder voor Node.js-applicaties.
npm i @tanstack/react-query
Integreer TanStack Query in de Next.js applicatie
Om TanStack Query in je Next.js project te integreren, is het noodzakelijk om een nieuwe instantie van TanStack Query in de kern van de applicatie op te zetten en te initialiseren - specifiek in het layout.js bestand. Dit kan worden bereikt door zowel QueryClient als QueryClientProvider te importeren van TanStack Query. Omcirkel vervolgens de eigenschap van het kind met QueryClientProvider, gestructureerd zoals hieronder getoond:
"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 };
Deze configuratie geeft TanStack Query volledige bevoegdheid om de huidige status van de software te begrijpen en te manipuleren.
Pagineren implementeren met de useQuery haak
Het gebruik van de useQuery
haak vergemakkelijkt het efficiënt ophalen en verwerken van gegevens door het opnemen van paginering attributen, waaronder paginanummers, om naadloos gerichte delen van informatie op te halen.
Advanced Repeat is zeer veelzijdig en biedt een scala aan mogelijkheden om het ophalen van gegevens aan te passen aan uw specifieke eisen. Dit omvat de mogelijkheid om caching-instellingen in te stellen en laadvoorwaarden eenvoudig te beheren, wat resulteert in een soepele en uniforme paginering.
Om de paginering in onze Next.js-applicatie op te nemen, maken we een bestand Pagination/page.js in de map “src/app” van de broncode. Dit specifieke bestand bevat de noodzakelijke importverklaringen voor het implementeren van de pagineerfunctie.
"use client"
import React, { useState } from 'react';
import { useQuery} from '@tanstack/react-query';
import './page.styles.css';
Definieer vervolgens een functioneel React-component. In dit component moet je een functie definiëren die gegevens ophaalt van een externe API. In dit geval gebruik je de JSONPlaceholder API om een reeks berichten op te halen.
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;
}
};
// add the following code here
}
De useQuery
haak kan worden gedefinieerd door een object te specificeren met verschillende key-waarde paren die de verschillende parameters vertegenwoordigen die nodig zijn om gegevens op te halen uit een GraphQL API. Deze parameters kunnen de query string zelf bevatten, variabelen om de query aan te passen, opties om te bepalen hoe de gegevens worden opgehaald en bijgewerkt, en beleid om opnieuw te proberen in het geval van netwerkfouten of andere problemen. Door deze parameters te verstrekken binnen de context van de useQuery
hook, stellen we de React component tree in staat om de status te beheren die is gekoppeld aan de levenscyclus van de query, waardoor efficiëntere updates en soepelere gebruikerservaringen mogelijk worden.
const { isLoading, isError, error, data } = useQuery({
keepPreviousData: true,
queryKey: ['posts', page],
queryFn: fetchPosts,
});
De eigenschap “keepPreviousData” is ingesteld op “true”, waardoor eerdere gegevens kunnen worden behouden bij het verkrijgen van nieuwe informatie. De variabele “queryKey” bevat een lijst met sleutels, waaronder het vereiste eindpunt en het gewenste paginanummer. Tot slot dient het aanroepen van de functie “fetchPosts” als trigger voor de gegevensverzameling.
In een eerdere discussie hebben we het feit aangestipt dat de hook meerdere toestanden biedt die kunnen worden gedeconstrueerd op een manier die analoog is aan de ontleding van arrays en objecten. Door deze toestanden te gebruiken, wordt het mogelijk om de algehele gebruikerservaring te verbeteren door geschikte interfaces weer te geven tijdens de fase van het ophalen van gegevens. De beschikbare opties zijn onder andere ‘isLoading’, ‘isError’ en diverse andere.
Om verschillende berichtenschermen weer te geven, afhankelijk van de huidige status van de lopende procedure, is het nodig om het meegeleverde codefragment op te nemen, waarmee verschillende berichtenschermen kunnen worden weergegeven voor elke fase van het lopende proces.
if (isLoading) {
return (<h2>Loading...</h2>);
}
if (isError) {
return (<h2 className="error-message">{error.message}</h2>);
}
Tot slot is het essentieel om de code te leveren voor de JavaScript-componenten die worden weergegeven in de webbrowser. Dit zorgt niet alleen voor een goede rendering van de componenten, maar het maakt ook communicatie mogelijk tussen de client-side en server-side applicaties door het gebruik van event handlers en data fetching methodes.
Door gebruik te maken van de functionaliteit van de useQuery haak, wordt een verzameling opgehaalde berichten effectief verzameld binnen de grenzen van de gegevensvariabele. Deze aggregatie dient om het onderhoud van de interne staat van de applicatie te vergemakkelijken. Vervolgens kan een traversal worden uitgevoerd op de accumulatie van berichten die zijn opgeslagen in de genoemde variabele, met als hoogtepunt hun visuele weergave op de bladerinterface.
Om gebruikers de mogelijkheid te geven om door extra gepagineerde gegevens te navigeren, is het noodzakelijk om twee navigatieknoppen te integreren, gelabeld “Vorige” en “Volgende”. Met deze knoppen kunnen gebruikers naar verdere pagina’s met inhoud gaan wanneer deze gepagineerd worden weergegeven.
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 ten slotte de ontwikkelserver.
npm run dev
Navigeer naar " http://localhost:3000/Pagination " in uw webbrowser voor verdere instructies.
Het opnemen van de Pagination component in de mappenstructuur van de applicatie zorgt ervoor dat Next.js het herkent als een aangewezen route, waardoor naadloze navigatie naar de corresponderende webpagina mogelijk wordt via de specifieke URL.
Oneindig scrollen met de useInfiniteQuery Hook
Oneindig scrollen creëert een schijnbaar ononderbroken gebruikersinterface door dynamisch extra inhoud te laden als de gebruiker blijft scrollen. Een voorbeeld hiervan kan worden gevonden in de functionaliteit van YouTube, waarin nieuwe video-items moeiteloos worden opgehaald en gepresenteerd zonder enige waarneembare onderbreking terwijl men door de webpagina daalt.
Het gebruik van de useInfiniteQuery
hook maakt het mogelijk om oneindig te scrollen door het ophalen van gegevens van een externe server, waarbij volgende pagina’s automatisch worden opgevraagd en weergegeven als de gebruiker steeds verder naar beneden gaat.
Om de functionaliteit voor oneindig scrollen in je applicatie op te nemen, moet je een nieuw JavaScript-bestand maken met de naam “InfiniteScroll/page.js” en dit in de map “src/app” plaatsen. Vervolgens moet je verschillende modules importeren, waaronder React-componenten en bibliotheken voor toestandbeheer, die de naadloze integratie van deze functie met je bestaande codebase vergemakkelijken.
"use client"
import React, { useRef, useEffect, useState } from 'react';
import { useInfiniteQuery } from '@tanstack/react-query';
import './page.styles.css';
Vervolgens zullen we een functioneel React-component ontwikkelen en daarbinnen een functie maken die de inhoud van de berichten ophaalt op een manier die analoog is aan de methode die wordt gebruikt voor paginering.
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;
}
};
// add the following code here
}
In tegenstelling tot de paginering-implementatie, die geen vertraging introduceert bij het ophalen van gegevens, bevat deze specifieke code een opzettelijke pauze van ongeveer twee seconden voordat nieuwe informatie wordt opgehaald. Deze opzettelijke vertraging is bedoeld om gebruikers ruim de tijd te geven om te scrollen en de huidige dataset te verkennen, wat uiteindelijk resulteert in het automatisch ophalen van een bijgewerkte set gegevens wanneer ze verder surfen.
Bij de initialisatie maakt de useInfiniteQuery
custom hook een verbinding met de server, waardoor de initiële set gegevens wordt opgehaald bij het renderen van de component. Als de gebruiker vervolgens door de inhoud bladert, haalt de haak zelfstandig volgende batches met informatie op en neemt deze op in de component zonder dat verdere invoer nodig is.
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) : [];
De posts
variabele dient als een accumulator voor het verzamelen van alle posts van verschillende pagina’s en plet ze in een verenigde matrix. Hierdoor wordt het proces van het doorlopen en weergeven van elk bericht afzonderlijk vereenvoudigd.
Men kan een functionaliteit implementeren die de Intersection Observer API gebruikt om vast te stellen wanneer specifieke elementen binnen de grenzen van het zichtbare scherm van de gebruiker komen door een functie te definiëren. Dit maakt het mogelijk om het scrollgedrag van de gebruiker in de gaten te houden en automatisch aanvullende gegevens te laden zodra ze het einde van een lijst naderen.
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]);
Neem tot slot de JSX-componenten op die in de webbrowser worden weergegeven.
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>
);
Na het voltooien van uw wijzigingen, navigeert u naar " http://localhost:3000/InfiniteScroll " om hun functionaliteit uit eerste hand te observeren.
TanStack Query: Meer dan alleen gegevens ophalen
TanStack Query toont zijn veelzijdigheid als uitgebreide bibliotheek voor gegevensbeheer door de implementatie van functies voor pagineren en oneindig scrollen. Deze functionaliteiten tonen het brede scala aan mogelijkheden van deze krachtige tool.
Door middel van een breed scala aan functionaliteiten optimaliseert deze oplossing het beheer van applicatiegegevens, met effectieve controle over de status. In combinatie met verschillende andere datacentrische operaties verbetert het de operationele efficiëntie en gebruikerstevredenheid van webgebaseerde applicaties.