Tutorial

Erstellen einer benutzerdefinierten Paginierung mit React

ApplicationsJavaScriptReact

Einführung

Wir sind oft an der Erstellung von Webanwendungen beteiligt, bei denen wir große Mengen von Datensätzen von einem Remote-Server, einer API oder einer Datenbank abrufen müssen. Wenn Sie beispielsweise ein Zahlungssystem entwickeln, könnten Tausende von Transaktionen abgerufen werden. Wenn es sich um eine Social Media-Anwendung handelt, könnten viele Benutzerkommentare, -profile oder -aktivitäten abgerufen werden. Was auch immer der Fall sein mag, es gibt verschiedene Lösungen, um Daten so darzustellen, dass der Endbenutzer, der mit der Anwendung interagiert, nicht überfordert wird.

Eine Methode zur Handhabung großer Datensätze ist die Verwendung der Paginierung. Die Paginierung funktioniert effektiv, wenn Sie die Größe des Datensatzes (die Gesamtzahl der Datensätze im Datensatz) bereits kennen. Zweitens laden Sie nur den erforderlichen Datenblock aus dem Gesamtdatensatz basierend auf der Interaktion des Endbenutzers mit der Paginierungssteuerung. Diese Technik wird bei der Anzeige der Suchergebnisse in der Google-Suche verwendet.

In diesem Tutorial lernen Sie, wie Sie mit React eine benutzerdefinierte Paginierungskomponente für die Paginierung großer Datensätze erstellen. Sie werden eine paginierte Ansicht der Länder der Welt erstellen – einen Datensatz mit einer bekannten Größe.

Hier ist eine Demo davon, was Sie in diesem Tutorial erstellen werden:

Screenshot der Demo-Anwendung — zeigt die Länder der Welt

Voraussetzungen

Um diesem Tutorial zu folgen, benötigen Sie:

  • Auf Ihrem Rechner nodejsinstalliertes [Node]. Die Schritte hierfür finden Sie unter Installieren von Node.js und Erstellen einer lokalen Entwicklungsumgebung.
  • Das Befehlszeilen-Paket [create-react-app][`create-react-app] zur Erstellung des Boilerplate-Codes für Ihre React-Anwendung. Wenn Sienpm < 5.2verwenden, müssen Siecreate-react-app` möglicherweise als globale Abhängigkeit installieren.
  • Schließlich geht dieses Tutorial davon aus, dass Sie bereits mit React vertraut sind. Sollte dies nicht der Fall sein, können Sie in der Reihe Codieren in React.js nachlesen, um mehr über React zu erfahren.

Dieses Tutorial wurde mit Node v14.2.0, nmp v6.14.4, react v16.13.1 und react-scripts v3.4.1 verifiziert.

Schritt 1 — Einrichten des Projekts

Starten Sie eine neue React-Anwendung unter Verwendung des Befehls create-react-app. Sie können diese Anwendung beliebig benennen. In diesem Tutorial wird die Anwendung react-pagination genannt:

  • npx create-react-app react-pagination

Als Nächstes installieren Sie die für Ihre Anwendung erforderlichen Abhängigkeiten. Verwenden Sie zunächst das Terminalfenster zur Navigation zum Projektverzeichnis:

  • cd react-pagination

Führen Sie den folgenden Befehl aus, um die erforderlichen Abhängigkeiten zu installieren:

  • npm install bootstrap@4.1.0 prop-types@15.6.1 react-flags@0.1.13 countries-api@2.0.1 node-sass@4.14.1

Dadurch werden bootstrap, prop-types, react-flags, countries-api und node-sass installiert.

Sie haben das Paket bootstrap als Abhängigkeit für Ihre Anwendung installiert, da Sie etwas Standardgestaltung benötigen. Sie verwenden auch Stile aus der pagination-Komponente von Bootstrap verwenden.

Um Bootstrap in die Anwendung einzubinden, bearbeiten Sie die Datei src/index.js:

  • nano src/index.js

Und fügen Sie die folgende Zeile vor den anderen import-Anweisungen hinzu:

src/index.js
import "bootstrap/dist/css/bootstrap.min.css";

Jetzt ist Bootstrap-Styling in Ihrer gesamten Anwendung verfügbar.

Außerdem haben Sie react-flags als Abhängigkeit für Ihre Anwendung installiert. Um Zugriff auf die Flaggen-Symbole aus Ihrer Anwendung zu erhalten, müssen Sie die Symbolbilder in das Verzeichnis public Ihrer Anwendung kopieren.

Erstellen Sie in Ihrem Verzeichnis public ein Verzeichnis img:

  • mkdir public/img

Kopieren Sie die Bilddateien in flags zu img:

  • cp -R node_modules/react-flags/vendor/flags public/img

Damit stellen Sie Ihrer Anwendung eine Kopie aller Bilder von react-flag bereit.

Nachdem Sie nun einige Abhängigkeiten eingebunden haben, starten Sie die Anwendung, indem Sie den folgenden Befehl mit npm aus dem Projektverzeichnis react-pagination ausführen:

  • npm start

Nachdem Sie die Anwendung gestartet haben, kann die Entwicklung beginnen. Beachten Sie, dass eine Browser-Registerkarte mit einer Live Neuladefunktionalität für Sie geöffnet wurde, um während der Entwicklung mit der Anwendung synchron zu bleiben.

Zu diesem Zeitpunkt sollte die Ansicht der Anwendung wie im folgenden Screenshot dargestellt aussehen:

Anfangsansicht – Willkommen bei React-Bildschirm

Sie sind nun bereit, mit der Erstellung von Komponenten zu beginnen.

Schritt 2 — Erstellen der Komponente CountryCard

In diesem Schritt erstellen Sie die Komponente CountryCard. Die Komponente CountryCard gibt den Namen, die Region und die Flagge eines bestimmten Landes wieder.

Zuerst erstellen wir ein Verzeichnis components im Verzeichnis src:

  • mkdir src/components

Anschließend erstellen wir eine neue Datei CountryCard.js im Verzeichnis src/works:

  • nano src/components/CountryCard.js

Und fügen den folgenden Code-Ausschnitt hinzu:

src/components/CountryCard.js
import React from 'react';
import PropTypes from 'prop-types';
import Flag from 'react-flags';

const CountryCard = props => {
  const {
    cca2: code2 = '', region = null, name = {}
  } = props.country || {};

  return (
    <div className="col-sm-6 col-md-4 country-card">
      <div className="country-card-container border-gray rounded border mx-2 my-3 d-flex flex-row align-items-center p-0 bg-light">
        <div className="h-100 position-relative border-gray border-right px-2 bg-white rounded-left">
          <Flag country={code2} format="png" pngSize={64} basePath="./img/flags" className="d-block h-100" />
        </div>
        <div className="px-3">
          <span className="country-name text-dark d-block font-weight-bold">{ name.common }</span>
          <span className="country-region text-secondary text-uppercase">{ region }</span>
        </div>
      </div>
    </div>
  )
}

CountryCard.propTypes = {
  country: PropTypes.shape({
    cca2: PropTypes.string.isRequired,
    region: PropTypes.string.isRequired,
    name: PropTypes.shape({
      common: PropTypes.string.isRequired
    }).isRequired
  }).isRequired
};

export default CountryCard;

Die Komponente CountryCard erfordert eine country-Prop, die die Daten über das wiederzugebende Land enthält. Wie in den propTypes für die Komponente CountryCard zu sehen ist, muss das Prop-Objekt country die folgenden Daten enthalten:

  • cca2 - 2-stelliger Ländercode
  • region - die Länderregion (z. B. „Afrika“)
  • name.common - der gebräuchliche Name des Landes (z. B. „Nigeria“)

Hier ist ein Beispiel für ein Länderobjekt:

{
  cca2: "NG",
  region: "Africa",
  name: {
    common: "Nigeria"
  }
}

Beachten Sie auch, wie Sie die Länderflagge mit dem Paket react-flags wiedergeben können. In der Dokumentation zu react-flags erfahren Sie mehr über die benötigten Props und die Verwendung des Pakets.

Sie haben nun eine einzelne Komponente CountryCard fertiggestellt. Letztendlich werden Sie CountryCards mehrfach verwenden, um verschiedene Flaggen und Länderinformationen in Ihrer Anwendung anzuzeigen.

Schritt 3 — Erstellen der Komponente Pagination

In diesem Schritt erstellen Sie die Komponente Pagination. Die Komponente Pagination enthält die Logik für das Erstellen, Rendern und Wechseln der Seiten auf der Paginierungssteuerung.

Erstellen Sie eine neue Datei Pagination.js im Verzeichnis src/components:

  • nano src/components/Pagination.js

Und fügen den folgenden Code-Ausschnitt hinzu:

src/components/Pagination.js
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';

class Pagination extends Component {
  constructor(props) {
    super(props);
    const { totalRecords = null, pageLimit = 30, pageNeighbours = 0 } = props;

    this.pageLimit = typeof pageLimit === 'number' ? pageLimit : 30;
    this.totalRecords = typeof totalRecords === 'number' ? totalRecords : 0;

    // pageNeighbours can be: 0, 1 or 2
    this.pageNeighbours = typeof pageNeighbours === 'number'
      ? Math.max(0, Math.min(pageNeighbours, 2))
      : 0;

    this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);

    this.state = { currentPage: 1 };
  }
}

Pagination.propTypes = {
  totalRecords: PropTypes.number.isRequired,
  pageLimit: PropTypes.number,
  pageNeighbours: PropTypes.number,
  onPageChanged: PropTypes.func
};

export default Pagination;

Die Komponente Pagination kann vier spezielle Props aufnehmen, wie im Objekt propTypes angegeben.

  • onPageChanged ist eine Funktion, die nur dann mit Daten des aktuellen Paginierungsstatus aufgerufen wird, wenn sich die aktuelle Seite ändert.
  • totalRecords gibt die Gesamtzahl der zu paginierenden Datensätze an. Es ist erforderlich.
  • pageLimit gibt die Anzahl der Datensätze an, die pro Seite angezeigt werden sollen. Wenn sie nicht angegeben wird, ist sie gemäß der Definition in der constructor() auf 30 voreingestellt.
  • pageNeighbours gibt die Anzahl der zusätzlichen Seitennummern an, die auf jeder Seite der aktuellen Seite angezeigt werden sollen. Der Mindestwert ist 0, und der maximale Wert ist 2. Wir hier nichts angegeben, wird der Standardwert 0 gemäß der Definition in der constructor() verwendet.

Das folgende Bild veranschaulicht die Wirkung verschiedener Werte der Prop pageNeighbours:

Darstellung der PageNeighbours

In der Funktion constructor() berechnen Sie die Gesamtseiten wie folgt:

this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);

Beachten Sie, dass Sie hier Math.ceil() verwenden, um sicherzustellen, dass Sie einen ganzzahligen Wert für die Gesamtzahl der Seiten erhalten. Dadurch wird auch sichergestellt, dass die überschüssigen Datensätze auf der letzten Seite erfasst werden, insbesondere in Fällen, in denen die Anzahl der überschüssigen Datensätze geringer ist als die Anzahl der pro Seite anzuzeigenden Datensätze.

Schließlich haben Sie den Status mit der Eigenschaft currentPage auf 1 initialisiert. Sie benötigen diese Statuseigenschaft, um intern den Überblick über die aktuell aktive Seite zu behalten.

Als Nächstes erstellen Sie die Methode zur Erzeugung der Seitennummern.

Fügen Sie nach import aber vor der Klasse Pagination die folgenden Konstanten und die Funktion range hinzu:

src/components/Pagination.js
// ...

const LEFT_PAGE = 'LEFT';
const RIGHT_PAGE = 'RIGHT';

/**
 * Helper method for creating a range of numbers
 * range(1, 5) => [1, 2, 3, 4, 5]
 */
const range = (from, to, step = 1) => {
  let i = from;
  const range = [];

  while (i <= to) {
    range.push(i);
    i += step;
  }

  return range;
}

Fügen Sie in der Klasse Pagination nach dem constructor die folgende Methode fetchPageNumbers hinzu:

src/components/Pagination.js
class Pagination extends Component {
  // ...

  /**
   * Let's say we have 10 pages and we set pageNeighbours to 2
   * Given that the current page is 6
   * The pagination control will look like the following:
   *
   * (1) < {4 5} [6] {7 8} > (10)
   *
   * (x) => terminal pages: first and last page(always visible)
   * [x] => represents current page
   * {...x} => represents page neighbours
   */
  fetchPageNumbers = () => {
    const totalPages = this.totalPages;
    const currentPage = this.state.currentPage;
    const pageNeighbours = this.pageNeighbours;

    /**
     * totalNumbers: the total page numbers to show on the control
     * totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
     */
    const totalNumbers = (this.pageNeighbours * 2) + 3;
    const totalBlocks = totalNumbers + 2;

    if (totalPages > totalBlocks) {
      const startPage = Math.max(2, currentPage - pageNeighbours);
      const endPage = Math.min(totalPages - 1, currentPage + pageNeighbours);
      let pages = range(startPage, endPage);

      /**
       * hasLeftSpill: has hidden pages to the left
       * hasRightSpill: has hidden pages to the right
       * spillOffset: number of hidden pages either to the left or to the right
       */
      const hasLeftSpill = startPage > 2;
      const hasRightSpill = (totalPages - endPage) > 1;
      const spillOffset = totalNumbers - (pages.length + 1);

      switch (true) {
        // handle: (1) < {5 6} [7] {8 9} (10)
        case (hasLeftSpill && !hasRightSpill): {
          const extraPages = range(startPage - spillOffset, startPage - 1);
          pages = [LEFT_PAGE, ...extraPages, ...pages];
          break;
        }

        // handle: (1) {2 3} [4] {5 6} > (10)
        case (!hasLeftSpill && hasRightSpill): {
          const extraPages = range(endPage + 1, endPage + spillOffset);
          pages = [...pages, ...extraPages, RIGHT_PAGE];
          break;
        }

        // handle: (1) < {4 5} [6] {7 8} > (10)
        case (hasLeftSpill && hasRightSpill):
        default: {
          pages = [LEFT_PAGE, ...pages, RIGHT_PAGE];
          break;
        }
      }

      return [1, ...pages, totalPages];
    }

    return range(1, totalPages);
  }
}

Hier definieren Sie zunächst zwei Konstanten: LEFT_PAGE und RIGHT_PAGE. Diese Konstanten werden verwendet, um Punkte anzugeben, an denen Sie Seitenkontrollen für das Verschieben nach links bzw. rechts haben.

Außerdem haben Sie eine Hilfsfunktion range() definiert, die Ihnen bei der Erstellung von Nummernbereichen helfen kann.

Anmerkung: Wenn Sie eine Dienstprogrammbibliothek wie Lodash in Ihrem Projekt verwenden, können Sie stattdessen die Funktion .range() von Lodash bereitgestellt. Der folgende Code-Ausschnitt zeigt den Unterschied zwischen der gerade definierten Funktion range() und der von Lodash:

range(1, 5); // returns [1, 2, 3, 4, 5]
_.range(1, 5); // returns [1, 2, 3, 4]

Als Nächstes haben Sie die Methode fetchPageNumbers() in der Klasse Pagination definiert. Diese Methode handhabt die Kernlogik für die Erstellung der Seitennummern, die auf der Paginierungssteuerung angezeigt werden sollen. Sie möchten, dass die erste Seite und die letzte Seite immer sichtbar sind.

Zuerst haben Sie einige Variablen definiert. totalNumbers stellt die Gesamtzahl der Seitennummern dar, die auf der Steuerung angezeigt werden. totalBlocks steht für die Gesamtseitennummern, die angezeigt werden sollen, plus zwei zusätzliche Blöcke für die Indikatoren der linken und der rechten Seite.

Wenn totalPages nicht größer als totalBlocks ist, geben Sie einen Zahlenbereich von 1 bis totalPages zurück. Andernfalls geben Sie den Bereich der Seitennummern mit LEFT_PAGE und RIGHT_PAGE an Punkten zurück, an denen die Seiten nach links bzw. rechts verschoben werden.

Beachten Sie jedoch, dass Ihre Paginierungssteuerung sicherstellt, dass die erste Seite und die letzte Seite immer sichtbar sind. Die Steuerungen für die linke und rechte Seite erscheinen nach innen.

Jetzt fügen Sie die Methode render() hinzu, mit der Sie die Paginierungssteuerung rendern können.

Fügen Sie in der Klasse Pagination nach der Methode constructor und fetchPageNumbers die folgende Methode render hinzu:

src/components/Pagination.js
class Pagination extends Component {
  // ...

  render() {
    if (!this.totalRecords || this.totalPages === 1) return null;

    const { currentPage } = this.state;
    const pages = this.fetchPageNumbers();

    return (
      <Fragment>
        <nav aria-label="Countries Pagination">
          <ul className="pagination">
            { pages.map((page, index) => {

              if (page === LEFT_PAGE) return (
                <li key={index} className="page-item">
                  <a className="page-link" href="#" aria-label="Previous" onClick={this.handleMoveLeft}>
                    <span aria-hidden="true">&laquo;</span>
                    <span className="sr-only">Previous</span>
                  </a>
                </li>
              );

              if (page === RIGHT_PAGE) return (
                <li key={index} className="page-item">
                  <a className="page-link" href="#" aria-label="Next" onClick={this.handleMoveRight}>
                    <span aria-hidden="true">&raquo;</span>
                    <span className="sr-only">Next</span>
                  </a>
                </li>
              );

              return (
                <li key={index} className={`page-item${ currentPage === page ? ' active' : ''}`}>
                  <a className="page-link" href="#" onClick={ this.handleClick(page) }>{ page }</a>
                </li>
              );

            }) }

          </ul>
        </nav>
      </Fragment>
    );
  }
}

Hier generieren Sie das Array der Seitennummern durch Aufruf der zuvor erstellten Methode fetchPageNumbers(). Dann rendern Sie jede Seitennummer mit Array.prototype.map(). Beachten Sie, dass Sie Click-Event-Handler für jede erstellte Seitennummer registrieren, um Klicks zu verarbeiten.

Beachten Sie auch, dass die Paginierungssteuerung nicht gerendert wird, wenn das Prop totalRecords nicht korrekt an die Komponente Pagination übergeben wurde oder in Fällen, in denen nur 1 Seite vorhanden ist.

Schließlich definieren Sie die Methoden für die Ereignishandler.

Fügen Sie in der Klasse Pagination nach der Methode constructor und fetchPageNumbers und der Methode render Folgendes hinzu:

src/components/Pagination.js
class Pagination extends Component {
  // ...

  componentDidMount() {
    this.gotoPage(1);
  }

  gotoPage = page => {
    const { onPageChanged = f => f } = this.props;
    const currentPage = Math.max(0, Math.min(page, this.totalPages));
    const paginationData = {
      currentPage,
      totalPages: this.totalPages,
      pageLimit: this.pageLimit,
      totalRecords: this.totalRecords
    };

    this.setState({ currentPage }, () => onPageChanged(paginationData));
  }

  handleClick = page => evt => {
    evt.preventDefault();
    this.gotoPage(page);
  }

  handleMoveLeft = evt => {
    evt.preventDefault();
    this.gotoPage(this.state.currentPage - (this.pageNeighbours * 2) - 1);
  }

  handleMoveRight = evt => {
    evt.preventDefault();
    this.gotoPage(this.state.currentPage + (this.pageNeighbours * 2) + 1);
  }
}

Sie definieren die Methode gotoPage(), die den Status ändert und die currentPage auf die angegebene Seite setzt. Sie stellt sicher, dass das Argument page einen Mindestwert von 1 und einen maximalen Wert der Gesamtzahl der Seiten hat. Schließlich ruft sie die Funktion onPageChanged() auf, die als Prop übergeben wurde, wobei die Daten den neuen Paginierungsstatus angeben.

Wenn die Komponente gemountet wird, gehen Sie zur ersten Seite, indem Sie this.gotoPage(1) aufrufen, wie in der Lebenszyklus-Methode this.gotoPage(1) gezeigt.

Beachten Sie, wie Sie (this.pageNeighbours * 2) in handleMoveLeft() und handleMoveRight() verwenden, um die Seitennummern basierend auf der aktuellen Seitennummer nach links bzw. rechts zu verschieben.

Hier ist eine Demonstration der Interaktion der Bewegung von links nach rechts.

Links-rechts-Bewegung der Interaktion

Sie haben nun die Komponente Pagination abgeschlossen. Benutzer können mit der Navigationssteuerung in dieser Komponente interagieren, um verschiedene Seiten von Flaggen anzuzeigen.

Schritt 4 — Erstellen der Komponente App

Nachdem Sie nun eine Komponente CountryCard und Pagination haben, können Sie sie in Ihrer Komponente App verwenden.

Ändern Sie die Datei App.js im Verzeichnis src:

  • nano src/App.js

Ersetzen Sie den Inhalt von App.js durch die folgenden Codezeilen:

src/App.js
import React, { Component } from 'react';
import Countries from 'countries-api';
import './App.css';
import Pagination from './components/Pagination';
import CountryCard from './components/CountryCard';

class App extends Component {
  state = { allCountries: [], currentCountries: [], currentPage: null, totalPages: null }

  componentDidMount() {
    const { data: allCountries = [] } = Countries.findAll();
    this.setState({ allCountries });
  }

  onPageChanged = data => {
    const { allCountries } = this.state;
    const { currentPage, totalPages, pageLimit } = data;
    const offset = (currentPage - 1) * pageLimit;
    const currentCountries = allCountries.slice(offset, offset + pageLimit);

    this.setState({ currentPage, currentCountries, totalPages });
  }
}

export default App;

Hier initialisieren Sie den Status der Komponente App mit den folgenden Attributen:

  • allCountries - dies ist ein Array aller Länder in Ihrer Anwendung. Initialisiert auf ein leeres Array ([]).
  • currentCountries - dies ist ein Array aller Länder, die auf der aktuell aktiven Seite angezeigt werden sollen. Initialisiert auf ein leeres Array ([]).
  • currentPage - die Seitennummer der aktuell aktiven Seite. Initialisiert auf null.
  • totalPages - die Gesamtzahl der Seiten für alle Ländereinträge. Initialisiert auf null.

Als Nächstes rufen Sie in der Lebenszyklusmethode componentDidMount() alle Länder der Welt mit dem Paket countries-api ab, indem Sie Countries.findAll() abrufen. Dann aktualisieren Sie den Status der Anwendung, indem Sie allCountries so einstellen, dass es alle Länder der Welt enthält. Um mehr über das Paket countries-apizu erfahren, können Sie die [Dokumentation countries-api] einsehen.

Schließlich haben Sie die Methode onPageChanged() definiert, die jedes Mal aufgerufen wird, wenn Sie über die Paginierungssteuerung zu einer neuen Seite navigieren. Diese Methode wird an das Prop onPageChanged der Komponente Pagination übergeben.

Es gibt zwei Zeilen, die bei dieser Methode beachtet werden sollten. Die erste ist diese Zeile:

const offset = (currentPage - 1) * pageLimit;

Der Wert offset gibt den Startindex zum Abrufen der Datensätze für die aktuelle Seite an. Die Verwendung von (currentPage - 1) stellt sicher, dass der Offset null ist. Nehmen wir zum Beispiel an, dass Sie 25 Datensätze pro Seite anzeigen, und Sie betrachten derzeit Seite 5. Dann ist der offset ((5 - 1) * 25 = 100).

Wenn Sie beispielsweise Datensätze bei Bedarf aus einer Datenbank abrufen, ist dies eine Beispiel-SQL-Abfrage, die Ihnen zeigt, wie Offset verwendet werden kann:

SELECT * FROM `countries` LIMIT 100, 25

Da Sie keine Datensätze aus einer Datenbank oder einer externen Quelle abrufen, benötigen Sie eine Möglichkeit, den erforderlichen Teil der Datensätze zu extrahieren, der für die aktuelle Seite angezeigt werden soll.

Die zweite ist diese Zeile:

const currentCountries = allCountries.slice(offset, offset + pageLimit);

Hier verwenden Sie die Methode Array.prototype.slice(), um den erforderlichen Teil der Datensätze aus allCountries zu extrahieren, indem Sie offset als Startindex für Slice und (offset + pageLimit) als den Index, vor dem Slice beendet werden soll, übergeben.

Anmerkung: In diesem Tutorial haben Sie keine Datensätze aus einer externen Quelle abgerufen. In einer realen Anwendung werden Sie wahrscheinlich Datensätze aus einer Datenbank oder einer API abrufen. Die Logik zum Abrufen der Datensätze kann in die Methode onPageChanged() der Komponente App eingebunden werden.

Nehmen wir an, Sie haben einen fiktiven API-Endpunkt /api/countries?page={current_page}&limit={page_limit}. Der folgende Ausschnitt zeigt, wie Sie mithilfe des HTTaxiosP-Pakets [axios] Länder bei Bedarf von der API abrufen können:

onPageChanged = data => {
  const { currentPage, totalPages, pageLimit } = data;

  axios.get(`/api/countries?page=${currentPage}&limit=${pageLimit}`)
    .then(response => {
      const currentCountries = response.data.countries;
      this.setState({ currentPage, currentCountries, totalPages });
    });
}

Jetzt können Sie die Komponente App beenden, indem Sie die Methode render() hinzufügen.

Fügen Sie in der Klasse App, jedoch nach componentDidMount und onPageChanged, die folgende Methode render hinzu:

src/App.js
class App extends Component {
  // ... other methods here ...

  render() {
    const { allCountries, currentCountries, currentPage, totalPages } = this.state;
    const totalCountries = allCountries.length;

    if (totalCountries === 0) return null;

    const headerClass = ['text-dark py-2 pr-4 m-0', currentPage ? 'border-gray border-right' : ''].join(' ').trim();

    return (
      <div className="container mb-5">
        <div className="row d-flex flex-row py-5">
          <div className="w-100 px-4 py-5 d-flex flex-row flex-wrap align-items-center justify-content-between">
            <div className="d-flex flex-row align-items-center">
              <h2 className={headerClass}>
                <strong className="text-secondary">{totalCountries}</strong> Countries
              </h2>
              { currentPage && (
                <span className="current-page d-inline-block h-100 pl-4 text-secondary">
                  Page <span className="font-weight-bold">{ currentPage }</span> / <span className="font-weight-bold">{ totalPages }</span>
                </span>
              ) }
            </div>
            <div className="d-flex flex-row py-4 align-items-center">
              <Pagination totalRecords={totalCountries} pageLimit={18} pageNeighbours={1} onPageChanged={this.onPageChanged} />
            </div>
          </div>
          { currentCountries.map(country => <CountryCard key={country.cca3} country={country} />) }
        </div>
      </div>
    );
  }
}

In der Methode render() rendern Sie die Gesamtzahl der Länder, die aktuelle Seite, die Gesamtzahl der Seiten, die Steuerung <Pagination> und dann die <CountryCard> für jedes Land auf der aktuellen Seite.

Beachten Sie, dass Sie die zuvor definierte Methode onPageChanged() an das Prop onPageChanged der Steuerung <Pagination> übergeben haben. Dies ist sehr wichtig für die Erfassung der Seitenänderungen aus der Komponente Pagination. Außerdem zeigen Sie 18 Länder pro Seite an.

Zu diesem Zeitpunkt sieht die Anwendung wie der folgende Screenshot aus:

Screenshot der Anwendung mit 248 aufgelisteten Ländern und Seitennummern oben, um durch die einzelnen Seiten zu gehen

Sie haben nun eine Komponente App, die mehrere Komponenten CountryCard anzeigt, und eine Komponente Pagination, die den Inhalt in separate Seiten aufteilt. Als Nächstes werden Sie das Styling Ihrer Anwendung erkunden.

Schritt 5 — Hinzufügen von benutzerdefinierten Stilen

Vielleicht haben Sie bemerkt, dass Sie den zuvor erstellten Komponenten einige benutzerdefinierte Klassen hinzugefügt haben. Lassen Sie uns einige Stil-Regeln für diese Klassen in der Datei src/App.scss definieren.

  • nano src/App.scss

Die Datei App.scss wird wie der folgende Ausschnitt aussehen:

src/App.scss
/* Declare some variables */
$base-color: #ced4da;
$light-background: lighten(desaturate($base-color, 50%), 12.5%);

.current-page {
  font-size: 1.5rem;
  vertical-align: middle;
}

.country-card-container {
  height: 60px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.country-name {
  font-size: 0.9rem;
}

.country-region {
  font-size: 0.7rem;
}

.current-page,
.country-name,
.country-region {
  line-height: 1;
}

// Override some Bootstrap pagination styles
ul.pagination {
  margin-top: 0;
  margin-bottom: 0;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);

  li.page-item.active {
    a.page-link {
      color: saturate(darken($base-color, 50%), 5%) !important;
      background-color: saturate(lighten($base-color, 7.5%), 2.5%) !important;
      border-color: $base-color !important;
    }
  }

  a.page-link {
    padding: 0.75rem 1rem;
    min-width: 3.5rem;
    text-align: center;
    box-shadow: none !important;
    border-color: $base-color !important;
    color: saturate(darken($base-color, 30%), 10%);
    font-weight: 900;
    font-size: 1rem;

    &:hover {
      background-color: $light-background;
    }
  }
}

Ändern Sie Ihre Datei App.js so, dass sie auf App.scss anstelle von App.css verweist.

Anmerkung: Weitere Informationen hierzu finden Sie in der Dokumentation zu Create React App.

  • nano src/App.js
src/App.js
import React, { Component } from 'react';
import Countries from 'countries-api';
import './App.scss';
import Pagination from './components/Pagination';
import CountryCard from './components/CountryCard';

Nach dem Hinzufügen der Stile wird die Anwendung nun wie der folgende Screenshot aussehen:

Screenshot der Anwendung, Seite 1 von 14, mit Stilen

Sie haben nun eine vollständige Anwendung mit zusätzlichem benutzerdefiniertem Styling. Sie können benutzerdefinierte Stile verwenden, um alle Standardstile, die von Bibliotheken wie Bootstrap bereitgestellt werden, zu ändern und zu verbessern.

Zusammenfassung

In diesem Tutorial haben Sie ein benutzerdefiniertes Paginierungs-Widget in Ihrer React-Anwendung erstellt. Obwohl Sie in diesem Tutorial keine Aufrufe an eine API getätigt oder mit einem Datenbank-Backend interagiert haben, kann Ihre Anwendung solche Interaktionen erfordern. Sie sind in keiner Weise auf den in diesem Tutorial verwendeten Ansatz beschränkt. Sie können ihn beliebig erweitern, um den Anforderungen Ihrer Anwendung gerecht zu werden.

Den vollständigen Quellcode dieses Tutorials finden Sie im Repository [build-react-pagination-demo][pagination-demo ]auf GitHub. Außerdem können Sie eine Live-Demo dieses Tutorials auf Code-Sandbox erhalten.

Wenn Sie mehr über React erfahren möchten, sehen Sie sich unsere Reihe Codieren in React.js an oder besuchen Sie unsere React-Themenseite für Übungen und Programmierprojekte.

Creative Commons License