Créer une pagination

Créer une pagination
19 octobre 2021

Dans ce chapitre nous allons nous pencher sur la pagination d'élements en prenant l'exemple des actualités.

Nous avons un un fichier src/pages/News.js qui affichent toutes nos actualités. Le problème est que si demain je me retrouve avec une centaine d'articles, et que je les affiche tous sur cette page, je risque de scroller longtemps, et l'internaute risque de passer outre ce qu'il cherche.

Nous allons donc créer une pagination.

Pour créer la pagination nous allons faire quelques modifications dans notre fichier de configuration des nodes gatsby : gatsby-node.js

/* gatsby-node.js */
const path = require("path");
exports.createPages = async function ({ actions, graphql }) {
  // Create news page with pagination
  const { data } = await graphql(`
    query nodes {
      allNodeNews {
        edges {
          node {
            path {
              alias
            }
          }
        }
      }
    }
  `);

  if (data.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`);
    return;
  }

  const AllNews = data.allNodeNews.edges;
  const newsPerPage = 2;
  const numPages = Math.ceil(AllNews.length / newsPerPage);
  Array.from({ length: numPages }).forEach((_, i) => {
    actions.createPage({
      path: i === 0 ? `/news` : `/news/${i + 1}`,
      component: path.resolve("./src/templates/News.js"),
      context: {
        limit: newsPerPage,
        skip: i * newsPerPage,
        numPages,
        currentPage: i + 1,
		url: `news`
      },
    });
  });

  // Create each news
  AllNews.forEach(edge => {
    const slug = edge.node.path.alias;
    actions.createPage({
      path: slug,
      component: require.resolve(`./src/pages/news/new.js`),
      context: { slug: slug },
    });
  });
};

Dans notre cas nous conservons la requête qui va chercher nos news, mais nous créons une nouvelle page avec la méthode createPage de gatsby.

Vous remarquerez que nous ajoutons les variables qui vont nous permettre de créer notre pagination dans l'objet context de la méthode createPage(). Pour rappel cet objet context nous permettra de récupérer ces valeurs dans notre page.

Vous remarquerez aussi que la valeur de component n'est pas celle que vous auriez pu imaginer ("/src/pages/news"). La raison est que Gatsby vous mettrait un warning lors de la compilation en vous expliquant qu'il existe déjà une route /news et qu'il ne serait plus en mesure de savoir quel code gère quelle route.

 

Je vais créer un nouveau composant pour afficher la pagination de mes actualités.

/* src/components/Pager.js */
import React from "react";
import { Link } from "gatsby";

const Pager = ({ pageContext }) => {
  const isFirst = pageContext.currentPage === 1;
  const isLast = pageContext.currentPage === pageContext.numPages;
  const prevPage = `${pageContext.url}/${(pageContext.currentPage - 1).toString()}`;
  const nextPage = `${pageContext.url}/${(pageContext.currentPage + 1).toString()}`;

  return (
    <nav className="mt-3" aria-label="Page navigation example">
      <ul className="pagination justify-content-center">
        {!isFirst && (
          <Link className="page-link" to={prevPage} rel="prev">←</Link>
        )}
        {Array.from({ length: pageContext.numPages }, (_, i) => (
          <li key={`pagination-number${i + 1}`} className={`page-item ${pageContext.currentPage === i + 1 ? "active" : ""}`}>
            <Link to={`/actualites/${i === 0 ? '' : i + 1}`} className="page-link">
              {i + 1}
            </Link>
          </li>
        ))}
        {!isLast && (
          <Link className="page-link" to={nextPage} rel="next">→</Link>
        )}
      </ul>
    </nav>
  );
};
export default Pager;

Nous allons maintenant supprimer notre page "src/pages/news.js" et créer un nouveau fichier "src/templates/News.js" en incluant notre nouveau Pager.

/* src/templates/News.js */
import * as React from "react";
import { graphql, Link } from "gatsby";
import Layout from "../components/Layout";
import SEO from "../components/Seo";
import Pager from "../components/Pager";

const ActualitesPage = ({ data, pageContext }) => {
  return (
    <Layout>
      <SEO
        title="Actualités"
        description="Ceci est la meta description de ma page d'actualités"
      />
      <main className="container">
        <h1 className="my-5 text-center">Actualités</h1>
        <div className="list-group">
          {data.allNodeNews.edges.map(({ node }) => (
            <Link
              className="list-group-item list-group-item-action d-flex gap-3 py-3"
              to={node.path.alias} key={node.title}>
              <img width="auto" height="64" alt={node.title} src={node.relationships.field_image.localFile.publicURL} />
              <div className="d-flex gap-2 w-100 justify-content-between align-items-center">
                <div>
                  <h2 className="mb-0 h6">{node.title}</h2>
                </div>
                <small className="opacity-50 text-nowrap">{new Date(node.changed).toLocaleDateString('fr-FR', {})}</small>
              </div>
            </Link>
          ))}
        </div>
        <Pager pageContext={pageContext} />
      </main>
    </Layout >
  );
};
export default ActualitesPage;

export const data = graphql`
  query News($skip: Int = 0, $limit: Int = 2) {
    allNodeNews(sort: {fields: created, order: DESC}, skip: $skip, limit: $limit) {
      edges {
        node {
          title
          drupal_internal__nid
          body {
            value
          }
          path {
            alias
          }
          relationships {
            field_image {
              localFile {
                url
                absolutePath
                publicURL
              }
            }
          }
          changed(formatString: "")
        }
      }
    }
  }
`;