Πώς να εφαρμόσετε την άπειρη κύλιση και σελιδοποίηση με το Next.js και το TanStack Query

Οι περισσότερες εφαρμογές που θα αναπτύξετε θα διαχειρίζονται δεδομένα. Καθώς τα προγράμματα συνεχίζουν να κλιμακώνονται, μπορεί να υπάρχει ολοένα και μεγαλύτερη ποσότητα από αυτό. Όταν οι εφαρμογές αποτυγχάνουν να διαχειριστούν αποτελεσματικά μεγάλους όγκους δεδομένων, έχουν κακή απόδοση.
Η σελιδοποίηση και η άπειρη κύλιση είναι δύο δημοφιλείς τεχνικές που μπορείτε να χρησιμοποιήσετε για να βελτιστοποιήσετε την απόδοση της εφαρμογής. Μπορούν να σας βοηθήσουν να χειριστείτε πιο αποτελεσματικά την απόδοση δεδομένων και να βελτιώσετε τη συνολική εμπειρία χρήστη.
Πίνακας περιεχομένων
Σελιδοποίηση και άπειρη κύλιση με χρήση ερωτήματος TanStack
Ερώτημα TanStack—μια προσαρμογή του React Query—είναι μια ισχυρή βιβλιοθήκη διαχείρισης κατάστασης για εφαρμογές JavaScript. Προσφέρει μια αποτελεσματική λύση για τη διαχείριση της κατάστασης της εφαρμογής, μεταξύ άλλων λειτουργιών, συμπεριλαμβανομένων εργασιών που σχετίζονται με δεδομένα, όπως η προσωρινή αποθήκευση.
Η σελιδοποίηση περιλαμβάνει τη διαίρεση ενός μεγάλου δεδομένων σε μικρότερες σελίδες, επιτρέποντας στους χρήστες να πλοηγούνται στο περιεχόμενο σε διαχειρίσιμα κομμάτια χρησιμοποιώντας κουμπιά πλοήγησης. Αντίθετα, η άπειρη κύλιση παρέχει μια πιο δυναμική εμπειρία περιήγησης. Καθώς ο χρήστης κάνει κύλιση, τα νέα δεδομένα φορτώνονται και εμφανίζονται αυτόματα, εξαλείφοντας την ανάγκη για ρητή πλοήγηση.
Η σελιδοποίηση και η άπειρη κύλιση στοχεύουν στην αποτελεσματική διαχείριση και παρουσίαση μεγάλων ποσοτήτων δεδομένων. Η επιλογή μεταξύ των δύο εξαρτάται από τις απαιτήσεις δεδομένων της εφαρμογής.
Μπορείτε να βρείτε τον κωδικό αυτού του έργου σε αυτό GitHub αποθήκη.
Ρύθμιση ενός έργου Next.js
Για να ξεκινήσετε, δημιουργήστε ένα έργο Next.js. Εγκαταστήστε την πιο πρόσφατη έκδοση του Next.js 13 που χρησιμοποιεί τον κατάλογο εφαρμογών.
npx create-next-app@latest next-project --app
Στη συνέχεια, εγκαταστήστε το πακέτο TanStack στο έργο σας χρησιμοποιώντας το npm, τον διαχειριστή πακέτων Node.
npm i @tanstack/react-query
Ενσωματώστε το TanStack Query στην εφαρμογή Next.js
Για να ενσωματώσετε το TanStack Query στο έργο σας Next.js, πρέπει να δημιουργήσετε και να αρχικοποιήσετε μια νέα παρουσία του TanStack Query στη ρίζα της εφαρμογής—το αρχείο layout.js. Για να το κάνετε αυτό, εισαγάγετε το QueryClient και το QueryClientProvider από το TanStack Query. Στη συνέχεια, τυλίξτε το παιδικό στηρίγμα με το QueryClientProvider ως εξής:
"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 };
Αυτή η ρύθμιση διασφαλίζει ότι το TanStack Query έχει πλήρη πρόσβαση στην κατάσταση της εφαρμογής.
Το άγκιστρο useQuery απλοποιεί την ανάκτηση και τη διαχείριση δεδομένων. Παρέχοντας παραμέτρους σελιδοποίησης, όπως αριθμούς σελίδων, μπορείτε εύκολα να ανακτήσετε συγκεκριμένα υποσύνολα δεδομένων.
Επιπλέον, το άγκιστρο παρέχει διάφορες επιλογές και διαμορφώσεις για την προσαρμογή της λειτουργικότητας ανάκτησης δεδομένων, συμπεριλαμβανομένης της ρύθμισης επιλογών προσωρινής μνήμης, καθώς και του αποτελεσματικού χειρισμού των καταστάσεων φόρτωσης. Με αυτές τις δυνατότητες, μπορείτε να δημιουργήσετε αβίαστα μια απρόσκοπτη εμπειρία σελιδοποίησης.
Τώρα, για να εφαρμόσετε τη σελιδοποίηση στην εφαρμογή Next.js, δημιουργήστε ένα αρχείο Pagination/page.js στον κατάλογο src/app. Μέσα σε αυτό το αρχείο, πραγματοποιήστε τις ακόλουθες εισαγωγές:
"use client"
import React, { useState } from 'react';
import { useQuery} from '@tanstack/react-query';
import './page.styles.css';
Στη συνέχεια, ορίστε ένα λειτουργικό στοιχείο React. Μέσα σε αυτό το στοιχείο, πρέπει να ορίσετε μια συνάρτηση που θα ανακτά δεδομένα από ένα εξωτερικό API. Σε αυτή την περίπτωση, χρησιμοποιήστε το JSONPlaceholder API για να ανακτήσετε ένα σύνολο αναρτήσεων.
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;
}
};
}
Τώρα, ορίστε το άγκιστρο useQuery και καθορίστε τις ακόλουθες παραμέτρους ως αντικείμενα:
const { isLoading, isError, error, data } = useQuery({
keepPreviousData: true,
queryKey: ['posts', page],
queryFn: fetchPosts,
});
Η τιμή keepPreviousData είναι αληθής, η οποία διασφαλίζει ότι, κατά την ανάκτηση νέων δεδομένων, η εφαρμογή διατηρεί τα προηγούμενα δεδομένα. Η παράμετρος queryKey είναι ένας πίνακας που περιέχει το κλειδί για το ερώτημα, σε αυτήν την περίπτωση, το τελικό σημείο και την τρέχουσα σελίδα για την οποία θέλετε να ανακτήσετε δεδομένα. Τέλος, η παράμετρος queryFn, fetchPosts, ενεργοποιεί την κλήση συνάρτησης για ανάκτηση δεδομένων.
Όπως αναφέρθηκε προηγουμένως, το άγκιστρο παρέχει πολλές καταστάσεις που μπορείτε να αποσυσκευάσετε, παρόμοια με τον τρόπο με τον οποίο θα καταστρέφατε πίνακες και αντικείμενα, και να τα χρησιμοποιήσετε για να βελτιώσετε την εμπειρία χρήστη (απόδοση κατάλληλων διεπαφής χρήστη) κατά τη διαδικασία ανάκτησης δεδομένων. Αυτές οι καταστάσεις περιλαμβάνουν το isLoading, το isError και άλλα.
Για να το κάνετε αυτό, συμπεριλάβετε τον ακόλουθο κώδικα για να αποδώσετε διαφορετικές οθόνες μηνυμάτων με βάση την τρέχουσα κατάσταση της εν εξελίξει διαδικασίας:
if (isLoading) {
return (<h2>Loading...</h2>);
}if (isError) {
return (<h2 className="error-message">{error.message}</h2>);
}
Τέλος, συμπεριλάβετε τον κώδικα για τα στοιχεία JSX που θα αποδοθούν στη σελίδα του προγράμματος περιήγησης. Αυτός ο κώδικας εξυπηρετεί επίσης δύο άλλες λειτουργίες:
- Μόλις η εφαρμογή ανακτήσει τις αναρτήσεις από το API, θα αποθηκευτούν στη μεταβλητή δεδομένων που παρέχεται από το άγκιστρο useQuery. Αυτή η μεταβλητή βοηθά στη διαχείριση της κατάστασης της εφαρμογής. Στη συνέχεια, μπορείτε να αντιστοιχίσετε τη λίστα των αναρτήσεων που είναι αποθηκευμένες σε αυτήν τη μεταβλητή και να τις αποδώσετε στο πρόγραμμα περιήγησης.
- Για να προσθέσετε δύο κουμπιά πλοήγησης, το Προηγούμενο και το Επόμενο, για να επιτρέψετε στους χρήστες να αναζητήσουν και να εμφανίσουν πρόσθετα σελιδοποιημένα δεδομένα ανάλογα.
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>
);
Τέλος, ξεκινήστε τον διακομιστή ανάπτυξης.
npm run dev
Στη συνέχεια, μεταβείτε στη διεύθυνση http://localhost:3000/Pagination σε ένα πρόγραμμα περιήγησης.
Εφόσον συμπεριλάβατε τον φάκελο Σελιδοποίηση στον κατάλογο της εφαρμογής, το Next.js τον αντιμετωπίζει ως διαδρομή, επιτρέποντάς σας να αποκτήσετε πρόσβαση στη σελίδα σε αυτήν τη διεύθυνση URL.
Η άπειρη κύλιση παρέχει μια απρόσκοπτη εμπειρία περιήγησης. Ένα καλό παράδειγμα είναι το YouTube, το οποίο ανακτά νέα βίντεο αυτόματα και τα εμφανίζει καθώς κάνετε κύλιση προς τα κάτω.
Το άγκιστρο useInfiniteQuery σάς επιτρέπει να εφαρμόσετε άπειρη κύλιση λαμβάνοντας δεδομένα από έναν διακομιστή σε σελίδες και αυτόματα ανάκτηση και απόδοση της επόμενης σελίδας δεδομένων καθώς ο χρήστης κάνει κύλιση προς τα κάτω.
Για να εφαρμόσετε άπειρη κύλιση, προσθέστε ένα αρχείο InfiniteScroll/page.js στον κατάλογο src/app. Στη συνέχεια, πραγματοποιήστε τις ακόλουθες εισαγωγές:
"use client"
import React, { useRef, useEffect, useState } from 'react';
import { useInfiniteQuery } from '@tanstack/react-query';
import './page.styles.css';
Στη συνέχεια, δημιουργήστε ένα λειτουργικό στοιχείο React. Μέσα σε αυτό το στοιχείο, παρόμοια με την υλοποίηση σελιδοποίησης, δημιουργήστε μια συνάρτηση που θα ανακτά τα δεδομένα των αναρτήσεων.
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;
}
};
}
Σε αντίθεση με την εφαρμογή σελιδοποίησης, αυτός ο κώδικας εισάγει μια καθυστέρηση δύο δευτερολέπτων κατά την ανάκτηση δεδομένων για να επιτρέψει στον χρήστη να εξερευνήσει τα τρέχοντα δεδομένα ενώ κάνει κύλιση για να ενεργοποιήσει μια εκ νέου ανάκτηση ενός νέου συνόλου δεδομένων.
Τώρα, ορίστε το άγκιστρο useInfiniteQuery. Όταν το στοιχείο προσαρτηθεί αρχικά, το άγκιστρο θα λάβει την πρώτη σελίδα δεδομένων από τον διακομιστή. Καθώς ο χρήστης κάνει κύλιση προς τα κάτω, το άγκιστρο θα ανακτήσει αυτόματα την επόμενη σελίδα δεδομένων και θα τα αποδώσει στο στοιχείο.
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) : [];
Η μεταβλητή αναρτήσεις συνδυάζει όλες τις αναρτήσεις από διαφορετικές σελίδες σε έναν ενιαίο πίνακα, με αποτέλεσμα μια ισοπεδωμένη έκδοση της μεταβλητής δεδομένων. Αυτό σας επιτρέπει να αντιστοιχίσετε και να αποδώσετε εύκολα τις μεμονωμένες αναρτήσεις.
Για να παρακολουθείτε κύλιση χρήστη και να φορτώνετε περισσότερα δεδομένα όταν ο χρήστης βρίσκεται κοντά στο κάτω μέρος της λίστας, μπορείτε να ορίσετε μια συνάρτηση που χρησιμοποιεί το Intersection Observer API για να ανιχνεύει πότε τα στοιχεία τέμνονται με τη θύρα προβολής.
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]);
Τέλος, συμπεριλάβετε τα στοιχεία JSX για τις αναρτήσεις που αποδίδονται στο πρόγραμμα περιήγησης.
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>
);
Αφού κάνετε όλες τις αλλαγές, επισκεφτείτε τη διεύθυνση http://localhost:3000/InfiniteScroll για να τις δείτε σε δράση.
Ερώτημα TanStack: Περισσότερα από απλή ανάκτηση δεδομένων
Η σελιδοποίηση και η άπειρη κύλιση είναι καλά παραδείγματα που τονίζουν τις δυνατότητες του TanStack Query. Με απλά λόγια, είναι μια ολοκληρωμένη βιβλιοθήκη διαχείρισης δεδομένων.
Με το εκτεταμένο σύνολο δυνατοτήτων του, μπορείτε να βελτιστοποιήσετε τις διαδικασίες διαχείρισης δεδομένων της εφαρμογής σας, συμπεριλαμβανομένου του αποτελεσματικού χειρισμού της κατάστασης. Παράλληλα με άλλες εργασίες που σχετίζονται με δεδομένα, μπορείτε να βελτιώσετε τη συνολική απόδοση των εφαρμογών Ιστού σας, καθώς και την εμπειρία χρήστη.