Jak implementovat nekonečné posouvání a stránkování pomocí Next.js a TanStack Query

Většina aplikací, které budete vyvíjet, bude spravovat data; jak se programy dále rozšiřují, může jich být stále větší množství. Když aplikace selhávají při efektivní správě velkého množství dat, fungují špatně.

Stránkování a nekonečné posouvání jsou dvě oblíbené techniky, které můžete použít k optimalizaci výkonu aplikace. Mohou vám pomoci efektivněji zvládnout vykreslování dat a zlepšit celkovou uživatelskou zkušenost.

Stránkování a nekonečné posouvání pomocí dotazu TanStack

Dotaz TanStack—adaptace React Query — je robustní knihovna pro správu stavu pro aplikace JavaScript. Nabízí efektivní řešení pro správu stavu aplikace, mimo jiné funkce, včetně úloh souvisejících s daty, jako je ukládání do mezipaměti.

Stránkování zahrnuje rozdělení velké datové sady na menší stránky, což uživatelům umožňuje procházet obsah ve spravovatelných částech pomocí navigačních tlačítek. Naproti tomu nekonečné posouvání poskytuje dynamičtější zážitek z prohlížení. Jak uživatel posouvá, nová data se automaticky načítají a zobrazují, takže není potřeba explicitní navigace.

Stránkování a nekonečné posouvání mají za cíl efektivně spravovat a prezentovat velké množství dat. Volba mezi těmito dvěma závisí na požadavcích aplikace na data.

Zde najdete kód tohoto projektu GitHub úložiště.

Nastavení projektu Next.js

Chcete-li začít, vytvořte projekt Next.js. Nainstalujte nejnovější verzi Next.js 13, která používá adresář App.

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

Dále nainstalujte balíček TanStack do svého projektu pomocí npm, správce balíčků Node.

 npm i @tanstack/react-query 

Integrujte TanStack Query do aplikace Next.js

Chcete-li integrovat TanStack Query do svého projektu Next.js, musíte vytvořit a inicializovat novou instanci TanStack Query v kořenovém adresáři aplikace – soubor layout.js. Chcete-li to provést, importujte QueryClient a QueryClientProvider z TanStack Query. Poté zabalte dětskou rekvizitu pomocí QueryClientProvider takto:

 "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 };

Toto nastavení zajišťuje, že TanStack Query má úplný přístup ke stavu aplikace.

  Naučte se nové dovednosti v roce 2022 s těmito aplikacemi

Hák useQuery zjednodušuje načítání a správu dat. Poskytnutím parametrů stránkování, jako jsou čísla stránek, můžete snadno načíst konkrétní podmnožiny dat.

Kromě toho hák poskytuje různé možnosti a konfigurace pro přizpůsobení vaší funkce načítání dat, včetně nastavení možností mezipaměti a také efektivního zacházení se stavy načítání. S těmito funkcemi můžete bez námahy vytvořit bezproblémové stránkování.

Chcete-li nyní implementovat stránkování v aplikaci Next.js, vytvořte soubor Pagination/page.js v adresáři src/app. Uvnitř tohoto souboru proveďte následující importy:

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

Poté definujte funkční komponentu React. Uvnitř této komponenty musíte definovat funkci, která bude získávat data z externího API. V tomto případě použijte JSONPlaceholder API k načtení sady příspěvků.

 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;
    }
  };

  
}

Nyní definujte háček useQuery a zadejte následující parametry jako objekty:

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

Hodnota keepPreviousData je true, což zajišťuje, že aplikace při načítání nových dat zachová předchozí data. Parametr queryKey je pole obsahující klíč pro dotaz, v tomto případě koncový bod a aktuální stránku, pro kterou chcete načíst data. Nakonec parametr queryFn, fetchPosts, spouští volání funkce k načtení dat.

Jak již bylo zmíněno dříve, hák poskytuje několik stavů, které můžete rozbalit, podobně jako byste destruovali pole a objekty, a využít je ke zlepšení uživatelské zkušenosti (vykreslování vhodných uživatelských rozhraní) během procesu načítání dat. Tyto stavy zahrnují isLoading, isError a další.

Chcete-li to provést, zahrňte následující kód k vykreslení různých obrazovek zpráv na základě aktuálního stavu probíhajícího procesu:

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

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

Nakonec zahrňte kód pro prvky JSX, které se vykreslí na stránce prohlížeče. Tento kód také slouží dvěma dalším funkcím:

  • Jakmile aplikace načte příspěvky z API, budou uloženy v datové proměnné poskytované hákem useQuery. Tato proměnná pomáhá spravovat stav aplikace. Poté můžete namapovat seznam příspěvků uložených v této proměnné a vykreslit je v prohlížeči.
  • Chcete-li přidat dvě navigační tlačítka, Předchozí a Další, aby uživatelé mohli podle toho vyhledávat a zobrazovat další stránkovaná 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>
  );

Nakonec spusťte vývojový server.

 npm run dev 

Poté přejděte v prohlížeči na adresu http://localhost:3000/Pagination.

  Jak se dívat na televizi s přáteli pomocí Hulu Watch Party

Vzhledem k tomu, že jste do adresáře aplikace zahrnuli složku Pagination, Next.js s ní zachází jako s trasou, která vám umožní přistupovat ke stránce na dané adrese URL.

Nekonečné posouvání poskytuje bezproblémové procházení. Dobrým příkladem je YouTube, který automaticky načítá nová videa a zobrazuje je při posouvání dolů.

Hák useInfiniteQuery umožňuje implementovat nekonečné posouvání načítáním dat ze serveru na stránkách a automatickým načítáním a vykreslováním další stránky dat, když uživatel posouvá dolů.

Chcete-li implementovat nekonečné posouvání, přidejte soubor InfiniteScroll/page.js do adresáře src/app. Poté proveďte následující importy:

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

Dále vytvořte funkční komponentu React. Uvnitř této komponenty, podobně jako v implementaci stránkování, vytvořte funkci, která bude načítat data příspěvků.

 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;
    }
  };

  
}

Na rozdíl od implementace stránkování tento kód zavádí dvousekundové zpoždění při načítání dat, aby umožnil uživateli prozkoumat aktuální data, zatímco se posouvají a spouštějí opětovné načtení nové sady dat.

  Zastavte automatické přehrávání animovaných GIFů ve vašem prohlížeči

Nyní definujte háček useInfiniteQuery. Když se komponenta zpočátku připojí, hák načte první stránku dat ze serveru. Když uživatel posouvá dolů, hák automaticky načte další stránku dat a vykreslí ji v komponentě.

   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) : [];

Proměnná posts kombinuje všechny příspěvky z různých stránek do jednoho pole, což vede ke sloučené verzi datové proměnné. To vám umožní snadno mapovat a vykreslovat jednotlivé příspěvky.

Chcete-li sledovat rolování uživatele a načítat další data, když se uživatel blíží ke konci seznamu, můžete definovat funkci, která využívá rozhraní Intersection Observer API ke zjištění, kdy se prvky protínají s výřezem.

   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]);

Nakonec zahrňte prvky JSX pro příspěvky, které se vykreslují v prohlížeči.

   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>
  );

Jakmile provedete všechny změny, navštivte http://localhost:3000/InfiniteScroll a uvidíte je v akci.

TanStack Query: Více než jen načítání dat

Stránkování a nekonečné posouvání jsou dobré příklady, které zvýrazňují možnosti TanStack Query. Jednoduše řečeno, je to všestranná knihovna pro správu dat.

Díky rozsáhlé sadě funkcí můžete zefektivnit procesy správy dat vaší aplikace, včetně efektivního zpracování stavu. Kromě dalších úloh souvisejících s daty můžete zlepšit celkový výkon vašich webových aplikací a také uživatelskou zkušenost.