Récupération de données dans Next.js - Comment utiliser SWR (useSwr)

Nov 04, 2020☕ ☕ 8 min Follow me on Twitter

Subscribe to receive the free weekly article

Next.js propose plusieurs méthodes pour récupérer les données, car il prend en charge le rendu côté client et côté serveur. La première consiste à utiliser SWR, qui est un ensemble de hooks React pour la récupération de données à distance.

Dans ce tutoriel, nous examinerons SWR, une bibliothèque qui facilite la mise en cache, la pagination, la revalidation, etc. Nous allons également créer une application Next (côté client) qui récupère les données depuis JSON Placeholder à l'aide de SWR.

Commençons!

Qu'est-ce que SWR?

SWR signifie stale-while-revalidate. C'est une bibliothèque légère créée par la même équipe derrière Next.js. Il permet de récupérer, de mettre en cache ou de faire une nouvelle requête de données en temps réel avec React Hooks. SWR procède en trois étapes: d'abord, il retourne le cache (passé), puis récupère les données du serveur (revalidation), et enfin vient avec les données à jour. De cette façon, SWR améliore votre expérience utilisateur en vous permettant de montrer quelque chose à votre utilisateur tout en récupérant les nouvelles données du serveur.

SWR est indépendant du backend, ce qui signifie que vous pouvez l'utiliser pour récupérer des données depuis n'importe quel serveur prenant en charge les requêtes HTTP. Il a également un bon support pour TypeScript et le rendu côté serveur. Contrairement à React, Next.js est livré avec SWR.

Cela dit, nous pouvons mettre la main à la pâte et configurer une nouvelle application Next.js pour utiliser les fonctionnalités SWR.

Configuration

Pour configurer une nouvelle application, nous allons utiliser Create Next App. Commencez par ouvrir votre interface de ligne de commande (CLI) et exécutez cette commande:

	npx create-next-app next-swr-app

Ensuite, structurez le dossier comme ceci:

├── components
| └── Post.js
├── pages
| └── index.js
├── useRequest.js
└── package.json

Décomposons la structure du fichier:

  • Post.js est le composant responsable de l'affichage de l'objet de post.
  • index.js est la page d'accueil de notre application.
  • useRequest.js est un hook personnalisé qui aide à récupérer les données en utilisant SWR.

Avec cette structure de dossiers en place, nous pouvons commencer à récupérer les données distantes à partir de JSON Placeholder dans la section suivante.

Récupération des données avec ʻuseSWR`

Pour récupérer des données distantes avec SWR, nous pouvons utiliser soit useSWR, soit useSWRInfinite. Cependant, il existe certaines différences entre les crochets. Le premier est utilisé uniquement pour la récupération de données, tandis que le second hook permet de récupérer et de paginer les données. Vous pouvez utiliser useSWRInfinite pour ajouter un défilement infinie ou une pagination dans votre application Next.js en un rien de temps.

Maintenant, explorons le fichier useRequest.js:

import useSWR from "swr"

const fetcher = url => fetch(url).then(res => res.json())
const baseUrl = "https://jsonplaceholder.typicode.com"

export const useGetPosts = path => {
  if (!path) {
    throw new Error("Path is required")
  }

  const url = baseUrl + path

  const { data: posts, error } = useSWR(url, fetcher)

  return { posts, error }
}

L'utilisation de ce hook personnalisé pour récupérer des données est facultative. Vous pouvez également utiliser les crochets SWR directement dans vos composants.

La fonction fetcher nous permet d'envoyer la requête HTTP au serveur, puis de transformer les données de réponse en JSON. La méthode fetch provient du paquet unfetch fourni avec Next.js.

Ensuite, nous utilisons la fonction useGetPosts pour envoyer la requête avec le hook useSWR. Il s'attend à recevoir comme arguments l'URL du serveur et une fonction fetcher pour exécuter la requête. Une fois les données récupérées, nous retournons les posts récupérés et un état error.

Avec ce hook personnalisé prêt à l'emploi, nous pouvons désormais créer les composants pour afficher les messages récupérés.

Création des composants

  • composants / Post.js
export default function Post({ post }) {
  const { title, body, id } = post
  return (
    <div className="Card">
      <h1 className="Card--title">
        {id}. {title}
      </h1>
      <p className="Card--body">{body}</p>
    </div>
  )
}

Comme vous pouvez le voir, nous avons un composant simple qui reçoit le post à afficher en tant que paramètre. Ensuite, nous utilisons la déstructuration pour extraire les éléments de l'objet afin d'afficher le post.

  • App.js
import { useGetPosts } from "../useRequest"
import Post from "../components/Post"

export default function IndexPage() {
  const { posts, error } = useGetPosts("/posts")

  if (error) return <h1>Something went wrong!</h1>
  if (!posts) return <h1>Loading...</h1>

  return (
    <div className="container">
      <h1>My Posts</h1>
      {posts.map(post => (
        <Post post={post} key={post.id} />
      ))}
    </div>
  )
}

Ici, nous commençons par importer le hook useGetPosts, puis nous passons le chemin comme argument pour exécuter la requête. Il renvoie les posts à afficher et un état d'erreur.

Après cela, nous utilisons le composant Post pour afficher le tableau de données. Si une erreur se produit, nous la traitons en conséquence avec l'etat error fournie par SWR.

Avec cette avancée, nous pouvons vérifier si tout fonctionne dans le navigateur. Pour ce faire, ouvrez le projet sur la CLI et exécutez la commande suivante:

  yarn dev

Ou pour npm

  npm run dev

Visitez sur le navigateur http://localhost:3000

app-preview-1

Génial! Nos données sont récupérées avec succès depuis le serveur en utilisant le hook useSWR.

Comme nous l'avons dit précédemment, SWR fournit un autre hook qui permet de paginer facilement les données. Mettons à jour notre application avec useSWRInfinite.

Pagination des données avec useSWRInfinite

Il est toujours possible d'utiliser le hook useSWR pour paginer les données, mais je ne le recommande pas car c'est du code supplémentaire et SWR propose déjà useSWRInfinite pour le faire.

  • useRequest.js
import { useSWRInfinite } from "swr"

const fetcher = url => fetch(url).then(res => res.json())
const baseUrl = "https://jsonplaceholder.typicode.com"

export const usePaginatePosts = path => {
  if (!path) {
    throw new Error("Path is required")
  }

  const url = baseUrl + path
  const PAGE_LIMIT = 5

  const { data, error, size, setSize } = useSWRInfinite(
    index => `${url}?_page=${index + 1}&_limit=${PAGE_LIMIT}`,
    fetcher
  )

  const posts = data ? [].concat(...data) : []
  const isLoadingInitialData = !data && !error
  const isLoadingMore =
    isLoadingInitialData ||
    (size > 0 && data && typeof data[size - 1] === "undefined")
  const isEmpty = data?.[0]?.length === 0
  const isReachingEnd =
    isEmpty || (data && data[data.length - 1]?.length < PAGE_LIMIT)

  return { posts, error, isLoadingMore, size, setSize, isReachingEnd }
}

Le hook useSWRInfinite attend comme argument une fonction qui retourne la clé de requête, une fonction fetcher, et des options. La clé de requête (index) est ce que SWR utilise pour savoir quelles données (page) récupérer. La valeur initiale de la clé de requête est 0, nous devons donc l'incrémenter de 1 à chaque demande. Le deuxième argument à définir sur l'URL est PAGE_LIMIT, qui est le nombre d'éléments à récupérer par requête.

useSWRInfinite renvoie plus de valeurs que cela. J'ai supprimé les données dont je n'ai pas besoin ici. Expliquons ce que font ces variables:

  • posts est le tableau des données extraites du serveur.
  • isLoadingInitialData vérifie s'il reste des données à récupérer.
  • isLoadingMore vérifie si nous récupérons actuellement des données.
  • isEmpty vérifie si le tableau de données est vide ou pas.
  • isReachingEnd vérifie si la limite de pages est atteinte ou pas.

Ensuite, nous retournons les valeurs afin de les utiliser dans nos composants.

  • App.js
import { usePaginatePosts } from "../useRequest"

import Post from "../components/Post"

export default function IndexPage() {
  const {
    posts,
    error,
    isLoadingMore,
    size,
    setSize,
    isReachingEnd,
  } = usePaginatePosts("/posts")

  if (error) return <h1>Something went wrong!</h1>
  if (!posts) return <h1>Loading...</h1>

  return (
    <div className="container">
      <h1>My Posts with useSWRInfinite</h1>
      {posts.map(post => (
        <Post post={post} key={post.id} />
      ))}
      <button
        disabled={isLoadingMore || isReachingEnd}
        onClick={() => setSize(size + 1)}
      >
        {isLoadingMore
          ? "Loading..."
          : isReachingEnd
          ? "No more posts"
          : "Load more"}
      </button>
    </div>
  )
}

Ici, nous importons d'abord usePaginatePosts, puis nous passons le point de terminaison de l'API comme argument. Ensuite, nous utilisons les valeurs renvoyées par le hook pour afficher les publications et charger de nouvelles données. Une fois que vous avez cliqué sur le bouton load more, SWR enverra la demande à la page suivante, puis renverra les données. Avec ceci en place, les données sont maintenant paginées à l'aide du hook useSWRInfinite.

Avec cette étape, nous pouvons tester si la pagination fonctionne en exécutant cette commande sur la CLI:

  yarn dev

Visitez sur le navigateur http://localhost:3000

app-preview-2

Et c'est tout! Notre application a l'air de bien fonctionner!

Nous avons fini d'utiliser la bibliothèque SWR côté client avec Next.js. Vous pouvez trouver le projet fini sur ce CodeSandbox.

Merci d'avoir lu!

#next

Support my work

Get articles in your inbox