One place for hosting & domains

      Erstellen

      Erstellen einer benutzerdefinierten Paginierung mit React


      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:

      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:

      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:

      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:

      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:

      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.

      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="https://www.digitalocean.com/community/tutorials/#" 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="https://www.digitalocean.com/community/tutorials/#" 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="https://www.digitalocean.com/community/tutorials/#" 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:

      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.

      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.

      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.



      Source link

      Erstellen einer REST-API mit Prisma und PostgreSQL


      Der Autor hat den Diversity in Tech Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      Einführung

      Prisma ist ein Open-Source-basiertes Datenbank-Toolkit. Es besteht aus drei Haupttools:

      • Prisma Client: Ein automatisch generierter und typensicherer Query Builder für Node.js und TypeScript.
      • Prisma Migrate: Ein deklaratives Modellierungs- und Migrationssystem für Daten.
      • Prisma Studio: Eine GUI zum Anzeigen und Bearbeiten von Daten in Ihrer Datenbank.

      Diese Tools dienen dazu, die Produktivität von Anwendungsentwicklern in ihren Datenbank-Workflows zu steigern. Einer der größten Vorteile von Prisma ist die Ebene der Abstraktion, die möglich ist: Anstatt komplexe SQL-Abfragen oder Schemamigrationen zu erstellen, können Anwendungsentwickler bei der Arbeit mit ihrer Datenbank unter Verwendung von Prisma Daten intuitiver verwalten.

      In diesem Tutorial erstellen Sie eine REST-API für eine kleine Blogging-Anwendung in TypeScript mithilfe von Prisma und eine PostgreSQL-Datenbank. Sie werden Ihre PostgreSQL-Datenbank mit Docker lokal einrichten und die REST-API mit Express implementieren. Am Ende des Tutorials verfügen Sie über einen Webserver, der auf Ihrem Rechner lokal ausgeführt wird und auf verschiedene HTTP-Anfragen reagieren sowie Daten in der Datenbank lesen und schreiben kann.

      Voraussetzungen

      Dieses Tutorial setzt Folgendes voraus:

      Grundlegende Vertrautheit mit TypeScript und REST-APIs ist hilfreich, für dieses Tutorial jedoch nicht erforderlich.

      Schritt 1 — Erstellen Ihres TypeScript-Projekts

      In diesem Schritt werden Sie mit npm ein einfaches TypeScript-Projekt einrichten. Dieses Projekt wird als Grundlage für die REST-API dienen, die Sie im Laufe dieses Tutorials erstellen werden.

      Erstellen Sie zunächst ein neues Verzeichnis für Ihr Projekt:

      Navigieren Sie als Nächstes in das Verzeichnis und initialisieren Sie ein leeres npm-Projekt. Beachten Sie, dass die Option -y hier bedeutet, dass Sie die interaktiven Eingabeaufforderungen des Befehls überspringen. Um die Eingabeaufforderungen zu durchlaufen, entfernen Sie -y aus dem Befehl:

      Weitere Details zu diesen Eingabeaufforderungen finden Sie in Schritt 1 unter Verwenden von Node.js-Modulen mit npm und package.json.

      Sie erhalten eine Ausgabe, die der folgenden ähnelt und die Standardantworten umfasst:

      Output

      Wrote to /.../my-blog/package.json: { "name": "my-blog", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

      Dieser Befehl erstellt eine minimale package.json-Datei, die Sie als Konfigurationsdatei für Ihr npm-Projekt verwenden können. Sie sind nun bereit, TypeScript in Ihrem Projekt zu konfigurieren.

      Führen Sie den folgenden Befehl für eine einfache TypeScript-Einrichtung aus:

      • npm install typescript ts-node @types/node --save-dev

      Dadurch werden drei Pakete als Entwicklungsabhängigkeiten in Ihrem Projekt installiert:

      • typescript: Die TypeScript-Toolchain.
      • ts-node: Ein Paket zum Ausführen von TypeScript-Anwendungen ohne vorherige Kompilierung in JavaScript.
      • @types/node: Die TypeScript-Typdefinitionen für Node.js.

      Die letzte Aufgabe besteht darin, eine tsconfig.json-Datei hinzuzufügen, um sicherzustellen, dass TypeScript für die von Ihnen erstellte Anwendung richtig konfiguriert ist.

      Führen Sie den folgenden Befehl aus, um die Datei zu erstellen:

      Fügen Sie in der Datei den folgenden JSON-Code hinzu:

      my-blog/tsconfig.json

      {
        "compilerOptions": {
          "sourceMap": true,
          "outDir": "dist",
          "strict": true,
          "lib": ["esnext"],
          "esModuleInterop": true
        }
      }
      

      Speichern und schließen Sie die Datei.

      Dies ist eine Standard- und Minimalkonfiguration für ein TypeScript-Projekt. Wenn Sie mehr über die einzelnen Eigenschaften der Konfigurationsdatei erfahren möchten, können Sie die TypeScript-Dokumentation konsultieren.

      Sie haben Ihr einfaches TypeScript-Projekt mit npm eingerichtet. Als Nächstes werden Sie Ihre PostgreSQL-Datenbank mit Docker einrichten und Prisma damit verbinden.

      Schritt 2 — Einrichten von Prisma mit PostgreSQL

      In diesem Schritt installieren Sie die Prisma-CLI , erstellen Ihre erste Prisma-Schemadatei, richten PostgreSQL mit Docker ein und verbinden Prisma damit. Das Prisma-Schema ist die wichtigste Konfigurationsdatei für Ihr Prisma-Setup und enthält das Datenbankschema.

      Installieren Sie zunächst die Prisma-CLI mit dem folgenden Befehl:

      • npm install @prisma/cli --save-dev

      Als bewährte Praxis wird empfohlen, die Prisma-CLI in Ihrem Projekt lokal zu installieren (und nicht im Rahmen einer globalen Installation). Dadurch lassen sich Versionskonflikte vermeiden, falls Sie mehr als ein Prisma-Projekt auf Ihrem Rechner verwenden.

      Als Nächstes richten Sie mit Docker Ihre PostgreSQL-Datenbank ein. Erstellen Sie mit dem folgenden Befehl eine neue Docker Compose-Datei:

      Fügen Sie der neu erstellten Datei den folgenden Code hinzu:

      my-blog/docker-compose.yml

      version: '3.8'
      services:
        postgres:
          image: postgres:10.3
          restart: always
          environment:
            - POSTGRES_USER=sammy
            - POSTGRES_PASSWORD=your_password
          volumes:
            - postgres:/var/lib/postgresql/data
          ports:
            - '5432:5432'
      volumes:
        postgres:
      

      Diese Docker Compose-Datei konfiguriert eine PostgreSQL-Datenbank, auf die über Port 5432 des Docker-Containers zugegriffen werden kann. Beachten Sie außerdem, dass die Anmeldedaten für die Datenbank aktuell sammy (Benutzer) und your_password (Passwort) lauten. Sie können diese Anmeldedaten in Ihren bevorzugten Benutzer und Ihr bevorzugtes Passwort ändern. Speichern und schließen Sie die Datei.

      Fahren Sie nun fort und starten Sie den PostgreSQL-Datenbankserver mit dem folgenden Befehl:

      Die Ausgabe dieses Befehls wird in etwa wie folgt aussehen:

      Output

      Pulling postgres (postgres:10.3)... 10.3: Pulling from library/postgres f2aa67a397c4: Pull complete 6de83ca23e55: Pull complete . . . Status: Downloaded newer image for postgres:10.3 Creating my-blog_postgres_1 ... done

      Sie können mit folgendem Befehl überprüfen, ob der Datenbankserver ausgeführt wird:

      Dadurch erhalten Sie eine Aufgabe, die in etwa wie folgt aussieht:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8547f8e007ba postgres:10.3 "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp my-blog_postgres_1

      Nachdem der Datenbankserver ausgeführt wird, können Sie nun Ihr Prisma-Setup erstellen. Führen Sie den folgenden Befehl über die Prisma-CLI aus:

      Dadurch erhalten Sie folgende Ausgabe:

      Output

      ✔ Your Prisma schema was created at prisma/schema.prisma. You can now open it in your favorite editor.

      Beachten Sie, dass Sie als bewährte Praxis allen Aufrufen der Prisma-CLI npx voranstellen sollten. Dadurch wird sichergestellt, dass Sie Ihre lokale Installation verwenden.

      Nachdem Sie den Befehl ausgeführt haben, erstellt die Prisma-CLI in Ihrem Projekt einen neuen Ordner namens prisma. Er enthält die folgenden zwei Dateien:

      • schema.prisma: Die Hauptkonfigurationsdatei für Ihr Prisma-Projekt (schließt Ihr Datenmodell mit ein).
      • .env: Eine dotenv-Datei zum Definieren Ihrer Datenbankverbindungs-URL.

      Um sicherzustellen, dass Prisma den Speicherort Ihrer Datenbank kennt, öffnen Sie die Datei .env und passen Sie die Umgebungsvariable DATABASE_URL an.

      Öffnen Sie zunächst die .env-Datei:

      Jetzt können Sie die Umgebungsvariable wie folgt setzen:

      my-blog/prisma/.env

      DATABASE_URL="postgresql://sammy:your_password@localhost:5432/my-blog?schema=public"
      

      Ändern Sie die Anmeldedaten für die Datenbank unbedingt auf jene, die Sie in der Docker Compose-Datei angegeben haben. Um mehr über das Format der Verbindungs-URL zu erfahren, besuchen Sie die Prisma-Dokumentation.

      Wenn Sie damit fertig sind, speichern und schließen Sie die Datei.

      In diesem Schritt haben Sie Ihre PostgreSQL-Datenbank mit Docker eingerichtet, die Prisma-CLI installiert und Prisma über eine Umgebungsvariable mit der Datenbank verbunden. Im nächsten Abschnitt definieren Sie Ihr Datenmodell und erstellen Ihre Datenbanktabellen.

      Schritt 3 — Definieren des Datenmodells und Erstellen von Datenbanktabellen

      In diesem Schritt definieren Sie Ihr Datenmodell in der Prisma-Schemadatei. Dieses Datenmodell wird dann mit Prisma Migrate der Datenbank zugeordnet; dadurch werden die SQL-Anweisungen generiert und gesendet, um die Tabellen zu erstellen, die Ihrem Datenmodell entsprechen. Da Sie eine Blogging-Anwendung erstellen, werden die wichtigsten Entitäten der Anwendung Benutzer und Beiträge sein.

      Prisma verwendet seine eigene Datenmodellierungssprache zum Definieren der Form Ihrer Anwendungsdaten.

      Öffnen Sie zunächst Ihre schema.prisma-Datei mit dem folgenden Befehl:

      • nano prisma/schema.prisma

      Fügen Sie nun folgende Modelldefinitionen hinzu. Sie können die Modelle am Ende der Datei platzieren, unmittelbar nach dem generator client-Block:

      my-blog/prisma/schema.prisma

      . . .
      model User {
        id    Int     @default(autoincrement()) @id
        email String  @unique
        name  String?
        posts Post[]
      }
      
      model Post {
        id        Int     @default(autoincrement()) @id
        title     String
        content   String?
        published Boolean @default(false)
        author    User?   @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql-de)
        authorId  Int?
      }
      

      Speichern und schließen Sie die Datei.

      Sie definieren zwei Modelle namens User und Post. Jedes von ihnen verfügt über eine Reihe vonFeldern, die die Eigenschaften des Modells darstellen. Die Modelle werden Datenbanktabellen zugeordnet; die Felder stellen die einzelnen Spalten dar.

      Beachten Sie außerdem, dass es eine one-to-many-Beziehung zwischen den beiden Modellen gibt, die von den Beziehungsfeldern posts und author in User und Post angegeben werden. Das bedeutet, dass ein Benutzer mit verschiedenen Beiträgen verknüpft sein kann.

      Nach Implementierung dieser Modelle können Sie nun unter Verwendung von Prisma Migrate die entsprechenden Tabellen in der Datenbank erstellen. Führen Sie in Ihrem Terminal folgenden Befehl aus:

      • npx prisma migrate save --experimental --create-db --name "init"

      Dieser Befehl erstellt in Ihrem Dateisystem eine neue Migration. Hier finden Sie einen kurzen Überblick über die drei Optionen, die dem Befehl bereitgestellt werden:

      • --experimental: Erforderlich, da Prisma Migrate derzeit in einem experimentellen Zustand ist.
      • --create-db: Ermöglicht Prisma Migrate die Erstellung der Datenbank mit dem Namen my-blog, die in der Verbindungs-URL angegeben ist.
      • --name "init": Gibt den Namen der Migration an (wird zum Benennen des Migrationsordners verwendet, der in Ihrem Dateisystem erstellt wird).

      Die Ausgabe dieses Befehls wird in etwa wie folgt aussehen:

      Output

      New datamodel: // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @default(autoincrement()) @id email String @unique name String? posts Post[] } model Post { id Int @default(autoincrement()) @id title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql-de) authorId Int? } Prisma Migrate just created your migration 20200811140708-init in migrations/ └─ 20200811140708-init/ └─ steps.json └─ schema.prisma └─ README.md

      Sie können die Migrationsdateien erkunden, die im Verzeichnis prisma/migrations erstellt wurden.

      Um die Migration für Ihre Datenbank auszuführen und die Tabellen für Ihre Prisma-Modelle zu erstellen, führen Sie in Ihrem Terminal folgenden Befehl aus:

      • npx prisma migrate up --experimental

      Sie erhalten die folgende Ausgabe:

      Output

      . . . Checking the datasource for potential data loss... Database Changes: Migration Database actions Status 20200811140708-init 2 CreateTable statements. Done 🚀 You can get the detailed db changes with prisma migrate up --experimental --verbose Or read about them here: ./migrations/20200811140708-init/README.md 🚀 Done with 1 migration in 206ms.

      Prisma Migrate generiert nun die SQL-Anweisungen, die für die Migration erforderlich sind, und sendet sie an die Datenbank. Im Folgenden sehen Sie die SQL-Anweisungen, die die Tabellen erstellt haben:

      CREATE TABLE "public"."User" (
        "id" SERIAL,
        "email" text  NOT NULL ,
        "name" text   ,
        PRIMARY KEY ("id")
      )
      
      CREATE TABLE "public"."Post" (
        "id" SERIAL,
        "title" text  NOT NULL ,
        "content" text   ,
        "published" boolean  NOT NULL DEFAULT false,
        "authorId" integer   ,
        PRIMARY KEY ("id")
      )
      
      CREATE UNIQUE INDEX "User.email" ON "public"."User"("email")
      
      ALTER TABLE "public"."Post" ADD FOREIGN KEY ("authorId")REFERENCES "public"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE
      

      In diesem Schritt haben Sie mit Prisma Migrate Ihr Datenmodell im Prisma-Schema definiert und die jeweiligen Datenbanktabellen erstellt. Im nächsten Schritt installieren Sie Prisma Client in Ihrem Projekt, damit Sie die Datenbank abfragen können.

      Schritt 4 — Erkunden von Prisma Client-Abfragen in einem einfachen Skript

      Prisma Client ist ein automatisch generierter und typensicherer Query Builder, mit dem Sie aus einer Node.js- oder TypeScript-Anwendung Daten in einer Datenbank programmatisch lesen und schreiben können. Sie werden ihn für Datenbankzugriff in Ihren REST-API-Routen verwenden, indem Sie traditionelle ORMs, einfache SQL-Abfragen, benutzerdefinierte Datenzugriffsebenen oder andere Methoden zur Kommunikation mit einer Datenbank ersetzen.

      In diesem Schritt installieren Sie Prisma Client und lernen die Abfragen kennen, die Sie damit senden können. Bevor Sie in den nächsten Schritten die Routen für Ihre REST-API implementieren, werden Sie zunächst einige der Prisma Client-Abfragen in einem einfachen ausführbaren Skript erkunden.

      Zuerst installieren Sie Prisma Client in Ihrem Projekt, indem Sie Ihr Terminal öffnen und das Prisma Client npm-Paket installieren:

      • npm install @prisma/client

      Erstellen Sie als Nächstes ein neues Verzeichnis namens src, das Ihre Quelldateien enthalten wird:

      Erstellen Sie nun in dem neuen Verzeichnis eine TypeScript-Datei:

      Alle Prisma Client-Abfragen geben promises (Zusagen) zurück, auf die Sie in Ihrem Code warten können. Dazu müssen Sie die Abfragen in einer async-Funktion senden.

      Fügen Sie den folgenden Codebaustein mit einer async-Funktion hinzu, die in Ihrem Skript ausgeführt wird:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        // ... your Prisma Client queries will go here
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      Hier finden Sie einen kurzen Überblick über den Codebaustein:

      1. Sie importieren den PrismaClient-Konstruktor aus dem zuvor installierten @prisma/client npm-Paket.
      2. Sie instanziieren PrismaClient, indem Sie den Konstrukteur aufrufen, und erhalten eine Instanz namens prisma.
      3. Sie definieren eine async-Funktion namens main, wo Sie als Nächstes Ihre Prisma Client-Abfragen hinzufügen werden.
      4. Sie rufen die main-Funktion auf, fangen dabei alle möglichen Ausnahmen ab und stellen sicher, dass Prisma Client alle offenen Datenbankverbindungen schließt, indem Sie prisma.disconnect() aufrufen.

      Nach Implementierung der main-Funktion können Sie mit dem Hinzufügen von Prisma Client-Abfragen in das Skript beginnen. Passen Sie index.ts wie folgt an:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        const newUser = await prisma.user.create({
          data: {
            name: 'Alice',
            email: 'alice@prisma.io',
            posts: {
              create: {
                title: 'Hello World',
              },
            },
          },
        })
        console.log('Created new user: ', newUser)
      
        const allUsers = await prisma.user.findMany({
          include: { posts: true },
        })
        console.log('All users: ')
        console.dir(allUsers, { depth: null })
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      In diesem Code verwenden Sie zwei Prisma Client-Abfragen:

      • create: Erstellt einen neuen User-Eintrag. Beachten Sie, dass Sie in Wahrheit ein nested write verwenden, was bedeutet, dass Sie in derselben Abfrage sowohl einen User– als auch einen Post-Eintrag erstellen.
      • findMany: Liest alle vorhandenen User-Einträge aus der Datenbank. Sie geben die include-Option an, wodurch zusätzlich auch die entsprechenden Post-Einträge für die einzelnen User-Einträge geladen werden.

      Führen Sie das Skript nun mit dem folgenden Befehl aus:

      Sie erhalten in Ihrem Terminal folgende Ausgabe:

      Output

      Created new user: { id: 1, email: 'alice@prisma.io', name: 'Alice' } [ { id: 1, email: 'alice@prisma.io', name: 'Alice', posts: [ { id: 1, title: 'Hello World', content: null, published: false, authorId: 1 } ] }

      Anmerkung: Wenn Sie eine Datenbank-GUI verwenden, können Sie überprüfen, ob die Daten erstellt wurden, indem Sie sich die Tabellen User und Post ansehen. Alternativ können Sie die Daten in Prisma Studio erkunden, indem Sie npx prisma studio --experimental ausführen.

      Sie haben Prisma Client nun verwendet, um Daten in Ihrer Datenbank zu lesen und zu schreiben. In den verbleibenden Schritten wenden Sie dieses neue Wissen an, um die Routen für eine beispielhafte REST-API zu implementieren.

      Schritt 5 — Implementieren Ihrer ersten REST-API-Route

      In diesem Schritt installieren Sie Express in Ihrer Anwendung. Express ist ein beliebtes Webframework für Node.js, das Sie zur Implementierung der REST-API-Routen in diesem Projekt verwenden werden. Die erste Route, die Sie implementieren werden, erlaubt es, mithilfe einer GET-Anfrage alle Benutzer von der API abzurufen. Die Benutzerdaten werden mit Prisma Client aus der Datenbank abgerufen.

      Installieren Sie dann Express mit dem folgenden Befehl:

      Da Sie TypeScript verwenden, sollten Sie die jeweiligen Typen auch als Entwicklungsabhängigkeiten installieren. Führen Sie dazu folgenden Befehl aus:

      • npm install @types/express --save-dev

      Nach Implementierung der Abhängigkeiten können Sie Ihre Express-Anwendung einrichten.

      Öffnen Sie dazu erneut Ihre zentrale Quelldatei:

      Löschen Sie nun den ganzen Code in index.ts und ersetzen Sie ihn durch Folgendes, um Ihre REST-API zu starten:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      import express from 'express'
      
      const prisma = new PrismaClient()
      const app = express()
      
      app.use(express.json())
      
      // ... your REST API routes will go here
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Hier finden Sie eine kurze Aufschlüsselung des Codes:

      1. Sie importieren PrismaClient und express aus den jeweiligen npm-Paketen.
      2. Sie instanziieren PrismaClient, indem Sie den Konstruktor aufrufen, und erhalten eine Instanz namens prisma.
      3. Sie erstellen Ihre Express-Anwendung, indem Sie express() aufrufen.
      4. Sie fügen die Middleware express.json() hinzu, um sicherzustellen, dass Express JSON-Daten ordnungsgemäß verarbeiten kann.
      5. Sie starten den Server unter Port 3000.

      Jetzt können Sie Ihre erste Route implementieren. Fügen Sie zwischen den Aufrufen für app.use und app.listen folgenden Code hinzu:

      my-blog/src/index.ts

      . . .
      app.use(express.json())
      
      app.get('/users', async (req, res) => {
        const users = await prisma.user.findMany()
        res.json(users)
      })
      
      app.listen(3000, () =>
      console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Speichern und schließen Sie anschließend Ihre Datei. Starten Sie dann mit dem folgenden Befehl Ihren lokalen Webserver:

      Sie erhalten die folgende Ausgabe:

      Output

      REST API server ready at: http://localhost:3000

      Um auf die Route /users zuzugreifen, können Sie Ihren Browser auf http://localhost:3000/users oder einen anderen HTTP-Client verweisen.

      In diesem Tutorial testen Sie alle REST-API-Routen mit curl (einem Terminal-basierten HTTP-Client).

      Anmerkung: Wenn Sie lieber einen GUI-basierten HTTP-Client verwenden, können Sie Alternativen wie Postwoman oder den Advanced REST Client verwenden.

      Öffnen Sie zum Testen Ihrer Route ein neues Terminalfenster oder eine Registerkarte (damit Ihr lokaler Webserver weiter ausgeführt werden kann) und führen Sie folgenden Befehl aus:

      • curl http://localhost:3000/users

      Sie erhalten die im vorherigen Schritt erstellten User-Daten:

      Output

      [{"id":1,"email":"alice@prisma.io","name":"Alice"}]

      Beachten Sie, dass das posts-Array diesmal nicht enthalten ist. Das liegt daran, dass Sie die Option include nicht an den findMany-Aufruf in der Implementierung der Route /users übergeben.

      Sie haben unter /users Ihre erste REST-API-Route implementiert. Im nächsten Schritt implementieren Sie die verbleibenden REST-API-Routen, um Ihrer API weitere Funktionen hinzuzufügen.

      Schritt 6 — Implementieren der verbleibenden REST-API-Routen

      In diesem Schritt implementieren Sie die verbleibenden REST-API-Routen für Ihre Blogging-Anwendung. Am Ende wird Ihr Webserver verschiedene GET-, POST-, PUT– und DELETE-Anfragen bereitstellen.

      Hier finden Sie einen Überblick über die verschiedenen Routen, die Sie implementieren werden:

      HTTP-Methode Route Beschreibung
      GET /feed Ruft alle veröffentlichten Beiträge ab.
      GET /post/:id Ruft einen einzelnen Beitrag anhand seiner ID ab.
      POST /user Erstellt einen neuen Benutzer.
      POST /post Erstellt einen neuen Beitrag (als Entwurf).
      PUT /post/publish/:id Setzt das published-Feld eines Beitrags auf true.
      DELETE post/:id Löscht einen Beitrag anhand seiner ID.

      Fahren Sie fort und implementieren Sie zunächst die verbleibenden GET-Routen.

      Öffnen Sie die Datei index.ts mit dem folgenden Befehl:

      Fügen Sie dann im Anschluss an die Implementierung der Route /users folgenden Code hinzu:

      my-blog/src/index.ts

      . . .
      
      app.get('/feed', async (req, res) => {
        const posts = await prisma.post.findMany({
          where: { published: true },
          include: { author: true }
        })
        res.json(posts)
      })
      
      app.get(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.findOne({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Speichern und schließen Sie Ihre Datei.

      Dieser Code implementiert die API-Routen für zwei GET-Anfragen:

      • /feed: Gibt eine Liste mit veröffentlichten Beiträgen zurück.
      • /post/:id: Gibt einen einzelnen Beitrag anhand seiner ID zurück.

      Prisma Client wird in beiden Implementierungen verwendet. In der Implementierung der Route /feed filtert die Abfrage, die Sie mit Prisma Client senden, nach allen Post-Einträgen, bei denen die Spalte published den Wert true enthält. Außerdem nutzt die Prisma Client-Abfrage include, um die entsprechenden author-Informationen für die einzelnen Beiträge abzurufen. In der Implementierung der Route /post/:id übergeben Sie die ID, die aus dem URL-Pfad abgerufen wird, um einen bestimmten Post-Eintrag aus der Datenbank zu lesen.

      Sie können den Server anhalten, indem Sie auf Ihrer Tastatur Strg+C drücken. Starten Sie dann den Server neu:

      Um die Route /feed zu testen, können Sie folgenden curl-Befehl verwenden:

      • curl http://localhost:3000/feed

      Da noch keine Beiträge veröffentlicht wurden, ist die Antwort ein leeres Array:

      Output

      []

      Um die Route /post/:id zu testen, können Sie folgenden curl-Befehl verwenden:

      • curl http://localhost:3000/post/1

      Dadurch wird der von Ihnen ursprünglich erstellte Beitrag zurückgegeben:

      Output

      {"id":1,"title":"Hello World","content":null,"published":false,"authorId":1}

      Implementieren Sie als Nächstes die beiden POST-Routen. Fügen Sie nach den Implementierungen der drei GET-Routen folgenden Code zu index.ts hinzu:

      my-blog/src/index.ts

      . . .
      
      app.post(`/user`, async (req, res) => {
        const result = await prisma.user.create({
          data: { ...req.body },
        })
        res.json(result)
      })
      
      app.post(`/post`, async (req, res) => {
        const { title, content, authorEmail } = req.body
        const result = await prisma.post.create({
          data: {
            title,
            content,
            published: false,
            author: { connect: { email: authorEmail } },
          },
        })
        res.json(result)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Wenn Sie damit fertig sind, speichern und schließen Sie die Datei.

      Dieser Code implementiert die API-Routen für zwei POST-Anfragen:

      • /user: Erstellt in der Datenbank einen neuen Benutzer.
      • /post: Erstellt in der Datenbank einen neuen Beitrag.

      Wie zuvor wird in beiden Implementierungen Prisma Client verwendet. In der Implementierung der Route /user übergeben Sie die Werte aus dem Haupttext der HTTP-Anfrage an die Prisma Client-Abfrage create.

      Die Route /post ist etwas aufwendiger: Hier können Sie die Werte aus dem Haupttext der HTTP-Anfrage nicht direkt übergeben; stattdessen müssen Sie sie zunächst manuell extrahieren, um sie dann an die Prisma Client-Abfrage zu übergeben. Der Grund dafür besteht darin, dass die Struktur von JSON im Haupttext der Anfrage nicht mit der Struktur übereinstimmt, die Prisma Client erwartet. Daher müssen Sie die erwartete Struktur manuell einrichten.

      Sie können die neuen Routen testen, indem Sie den Server mit Strg+C anhalten. Starten Sie dann den Server neu:

      Um über die Route /user einen neuen Benutzer zu erstellen, können Sie mit curl folgende POST-Anfrage senden:

      • curl -X POST -H "Content-Type: application/json" -d '{"name":"Bob", "email":"bob@prisma.io"}' http://localhost:3000/user

      Dadurch wird in der Datenbank ein neuer Benutzer erstellt und folgende Ausgabe ausgedruckt:

      Output

      {"id":2,"email":"bob@prisma.io","name":"Bob"}

      Um über die Route /post einen neuen Beitrag zu erstellen, können Sie mit curl folgende POST-Anfrage senden:

      • curl -X POST -H "Content-Type: application/json" -d '{"title":"I am Bob", "authorEmail":"bob@prisma.io"}' http://localhost:3000/post

      Dadurch wird in der Datenbank ein neuer Beitrag erstellt und unter Verwendung der E-Mail-Adresse bob@prisma.io mit dem Benutzer verbunden. Sie erhalten die folgende Ausgabe:

      Output

      {"id":2,"title":"I am Bob","content":null,"published":false,"authorId":2}

      Schließlich können Sie die Routen PUT und DELETE implementieren.

      Öffnen Sie die Datei index.ts mit dem folgenden Befehl:

      Fügen Sie dann nach der Implementierung der beiden POST-Routen den hervorgehobenen Code hinzu:

      my-blog/src/index.ts

      . . .
      
      app.put('/post/publish/:id', async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.update({
          where: { id: Number(id) },
          data: { published: true },
        })
        res.json(post)
      })
      
      app.delete(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.delete({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Speichern und schließen Sie Ihre Datei.

      Dieser Code implementiert die API-Routen für eine PUT– sowie eine DELETE-Anfrage.

      • /post/publish/:id (PUT): Veröffentlicht einen Beitrag anhand seiner ID.
      • /post/:id (DELETE) Löscht einen Beitrag anhand seiner ID.

      Erneut wird Prisma Client in beiden Implementierungen verwendet. In der Implementierung der Route /post/publish/:id wird die ID des zu veröffentlichenden Beitrags von der URL abgerufen und an die update-Abfrage von Prisma Client übergeben. Die Implementierung der Route /post/:id zum Löschen eines Beitrags in der Datenbank ruft außerdem die Beitrags-ID aus der URL ab und übergibt sie an die delete-Abfrage von Prisma Client.

      Halten Sie den Server mit Strg+C auf Ihrer Tastatur erneut an. Starten Sie dann den Server neu:

      Sie können die Route PUT mit dem folgenden curl-Befehl testen:

      • curl -X PUT http://localhost:3000/post/publish/2

      Dadurch wird der Beitrag mit einem ID-Wert von 2 veröffentlicht. Wenn Sie die Anfrage /feed neu senden, wird dieser Beitrag nun in die Antwort aufgenommen.

      Abschließend können Sie die Route DELETE mit dem folgenden curl-Befehl testen:

      • curl -X DELETE http://localhost:3000/post/1

      Dadurch wird der Beitrag mit dem ID-Wert von 1 gelöscht. Um zu überprüfen, ob der Beitrag mit dieser ID gelöscht wurde, können Sie erneut eine GET-Anfrage an die Route /post/1 senden.

      In diesem Schritt haben Sie die verbleibenden REST-API-Routen für Ihre Blogging-Anwendung implementiert. Die API reagiert nun auf verschiedene GET-, POST-, PUT– und DELETE-Anfragen und implementiert Funktionen zum Lesen und Schreiben von Daten in der Datenbank.

      Zusammenfassung

      In diesem Artikel haben Sie eine REST-API mit einer Reihe von verschiedenen Routen erstellt, um Benutzer- und Beitragsdaten für eine beispielhafte Blogging-Anwendung zu erstellen, zu lesen, zu aktualisieren und zu löschen. Innerhalb der API-Routen haben Sie den Prisma Client zum Senden der entsprechenden Abfragen an Ihre Datenbank verwendet.

      Als Nächstes können Sie weitere API-Routen implementieren oder Ihr Datenbankschema mithilfe von Prisma Migrate erweitern. Konsultieren Sie die Prisma-Dokumentation, um mehr über verschiedene Aspekte von Prisma zu erfahren und einige sofort einsatzbereite Beispielprojekte zu erkunden (im Repository prisma-examples). Verwenden Sie dazu Tools wie GraphQL oder grPC APIs.



      Source link

      Erstellen eines Discord-Bots mit Node.js


      Der Autor wählte den Free and Open Source Fund, um eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      Einführung

      Discord ist eine Chat-Anwendung, die Millionen von Benutzern auf der ganzen Welt für Messaging und Voice Chat nutzen – in Communities, die Gilden oder Server genannt werden. Außerdem bietet Discord eine umfangreiche API, die Entwickler zum Einrichten leistungsfähiger Discord-Bots verwenden können. Bots können verschiedene Aktionen wie das Senden von Nachrichten an Server, das Ausführen von DM-Befehlen für Benutzer, das Moderieren von Servern und das Abspielen von Audio in Voice Chats erledigen. So können Entwickler leistungsstarke Bots entwickeln, die erweiterte, anspruchsvolle Merkmale wie Moderationstools oder auch Spiele umfassen. Der Utility-Bot Dyno zum Beispiel stellt Millionen von Gilden bereit und bietet nützliche Merkmale wie Spamschutz, einen Musikplayer und andere Dienstprogrammfunktionen. Wenn Sie wissen, wie man Discord-Bots erstellt, können Sie viele Möglichkeiten implementieren, mit denen Tausende von Menschen täglich interagieren können.

      In diesem Tutorial erstellen Sie von Grund auf einen Discord-Bot mit Node.js und der Discord.js-Bibliothek, sodass Benutzer direkt mit der Discord-API interagieren können. Sie werden ein Profil für einen Discord-Bot einrichten, Authentifizierungstoken für den Bot erhalten und den Bot mit der Fähigkeit zur Verarbeitung von Befehlen mit Argumenten von Benutzern programmieren.

      Voraussetzungen

      Bevor Sie beginnen, benötigen Sie Folgendes:

      Schritt 1 — Einrichten eines Discord-Bots

      In diesem Schritt verwenden Sie die Entwickler-GUI von Discord, um einen Discord-Bot einzurichten und das Token des Bots zu empfangen, das Sie an Ihr Programm übergeben werden.

      Um einen Bot in der Discord-Plattform zu registrieren, verwenden Sie das Dashboard der Discord-Anwendung. Hier können Entwickler Discord-Anwendungen einschließlich Discord-Bots erstellen.

      Abbildung des Dashboards der Discord-Anwendung nach dem ersten Besuch von https://discord.com/developers/applications

      Um zu beginnen, klicken Sie auf Neue Anwendung. Discord wird Sie bitten, einen Namen für Ihre neue Anwendung einzugeben. Klicken Sie dann auf Erstellen, um die Anwendung zu erstellen.

      Abbildung der Eingabeaufforderung für die Erstellung einer Anwendung, mit „Test Node.js Bot“ als Name der Anwendung

      Anmerkung: Der Name Ihrer Anwendung ist unabhängig vom Namen des Bots und der Bot muss nicht den gleichen Namen tragen wie die Anwendung.

      Öffnen Sie nun Ihr Anwendungs-Dashboard. Um der Anwendung einen Bot hinzuzufügen, navigieren Sie links in der Navigationsleiste zur Registerkarte Bot.

      Abbildung der Registerkarte Bot des Anwendungs-Dashboards

      Klicken Sie auf die Schaltfläche Bot hinzufügen, um der Anwendung einen Bot hinzuzufügen. Klicken Sie auf die Schaltfläche Ja, los!, wenn sie Sie zur Bestätigung aufgefordert werden. Nun befinden Sie sich in einem Dashboard, das Details wie den Namen des Bots, das Authentifizierungstoken und das Profilbild enthält.

      Dashboard mit Details Ihres Bots

      Sie können den Namen oder das Profilbild Ihres Bots hier im Dashboard ändern. Außerdem müssen Sie das Authentifizierungstoken des Bots kopieren, indem Sie auf Klicken, um Token anzuzeigen klicken und das angezeigte Token kopieren.

      Achtung: Teilen oder laden Sie Ihr Bot-Token niemals hoch, damit sich andere Personen nicht bei Ihrem Bot anmelden können.

      Jetzt müssen Sie eine Einladung erstellen, mit der Sie die Discord-Gilden des Bots hinzufügen, in denen Sie den Bot testen können. Navigieren Sie zunächst zum Tab OAuth2 des Anwendungs-Dashboards. Um eine Einladung zu erstellen, scrollen Sie nach unten und wählen Sie unter Bereiche Bot aus. Außerdem müssen Sie Berechtigungen festlegen, um zu kontrollieren, welche Aktionen Ihr Bot in Gilden ausführen darf. Wählen Sie für die Zwecke dieses Tutorials Administrator, wodurch Ihr Bot die Berechtigung erhält, fast alle Aktionen in Gilden auszuführen. Kopieren Sie den Link mit der Schaltfläche Kopieren.

      OAuth2-Registerkarte, mit dem Bereich auf „bot“ und Berechtigungen auf „administator“ gesetzt

      Als Nächstes fügen Sie den Bot einem Server hinzu. Folgen Sie dem gerade erstellten Einladungs-Link. Sie können den Bot jedem Server hinzufügen, den Sie besitzen oder für den Sie über Administratorberechtigungen verfügen (über das Dropdownmenü).

      Seite nach dem Folgen des Einladungs-Links, über die Benutzer den Bot Servern hinzufügen können

      Klicken Sie nun auf Weiter. Stellen Sie sicher, dass Sie das Kontrollkästchen neben Administrator aktiviert haben – dadurch erhält der Bot Administratorberechtigungen. Klicken Sie dann auf Autorisieren. Discord wird Sie bitten, eine CAPTCHA zu lösen, bevor der Bot dem Server beitritt. Sie werden den Discord-Bot nun auf der Mitgliederliste in dem Server sehen, dem Sie den Bot unter offline hinzugefügt haben.

      Mitgliederliste eines Discord-Servers mit dem neu erstellten Bot unter dem Abschnitt „offline“ der Mitgliederliste

      Sie haben erfolgreich einen Discord-Bot erstellt und einem Server hinzugefügt. Als Nächstes schreiben Sie ein Programm, um sich bei dem Bot anzumelden.

      Schritt 2 — Erstellen Ihres Projekts

      In diesem Schritt richten Sie die grundlegende Codierungsumgebung ein, in der Sie Ihren Bot erstellen und sich programmatisch beim Bot anmelden werden.

      Zuerst müssen Sie einen Projektordner und die erforderlichen Projektdateien für den Bot einrichten.

      Erstellen Sie Ihren Projektordner:

      Wechseln Sie in den gerade erstellten Projektordner:

      Als Nächstes verwenden Sie Ihren Texteditor, um eine Datei namens config.json zu erstellen und das Authentifizierungstoken Ihres Bots zu speichern:

      Fügen Sie dann den folgenden Code der config-Datei hinzu und ersetzen Sie den hervorgehobenen Text durch das Authentifizierungstoken Ihres Bots:

      config.json

      {
          "BOT_TOKEN": "YOUR BOT TOKEN"
      }
      

      Speichern und schließen Sie die Datei.

      Als Nächstes erstellen Sie eine package.json-Datei, in der Details Ihres Projekts und Informationen über die Abhängigkeiten gespeichert werden, die Sie für das Projekt verwenden werden. Sie erstellen eine package.json-Datei, indem Sie den folgenden npm-Befehl ausführen:

      npm wird Sie nach verschiedenen Details zu Ihrem Projekt fragen. Wenn Sie eine Anleitung für diese Eingabeaufforderungen wünschen, konsultieren Sie Verwenden von Node.js-Modulen mit npm und package.json.

      Sie installieren nun das discord.js-Paket, das Sie zur Interaktion mit der Discord-API verwenden werden. Sie können discord.js über npm mit dem folgenden Befehl installieren:

      Nachdem Sie die Konfigurationsdatei eingerichtet und die erforderliche Abhängigkeit installiert haben, können Sie nun mit der Einrichtung Ihres Bots beginnen. In einer realen Anwendung würde ein großer Bot auf viele Dateien verteilt, aber für die Zwecke dieses Tutorials wird sich der Code Ihres Bots in einer Datei befinden.

      Erstellen Sie zunächst für den Code eine Datei mit dem Namen index.js im Ordner discord-bot:

      Beginnen Sie mit dem Codieren des Bots, indem Sie die discord.js-Abhängigkeit und die Konfigurationsdatei mit dem Token des Bots vorschreiben:

      index.js

      const Discord = require("discord.js");
      const config = require("./config.json");
      

      Fügen Sie danach die folgenden zwei Codezeilen hinzu:

      index.js

      ...
      const client = new Discord.Client();
      
      client.login(config.BOT_TOKEN);
      

      Speichern und schließen Sie Ihre Datei.

      Die erste Zeile des Codes erstellt einen neuen Discord.Client und weist ihn der Konstanten client zu. Dieser Client ist ein Teil davon, wie Sie mit der Discord-API interagieren werden und wie Discord Sie bei Ereignissen wie neuen Meldungen benachrichtigen wird. Der Client ist in Wirklichkeit der Discord-Bot.

      Die zweite Zeile des Codes verwendet die login-Methode für den Client, um sich bei dem von Ihnen erstellten Discord-Bot anzumelden, wobei das Token in der Datei config.json als Passwort verwendet wird. Mit dem Token erfährt die Discord-API, an welches Programm sich der Bot richtet und dass Sie für die Nutzung des Bots authentifiziert sind.

      Führen Sie nun mit Node die Datei index.js aus:

      Der Status Ihres Bots wird sich auf dem Discord-Server, dem er hinzugefügt wurde, in „online“ ändern.

      Abbildung des Bots im Online-Zustand

      Sie haben erfolgreich eine Codierungsumgebung eingerichtet und den grundlegenden Code für die Anmeldung bei einem Discord-Bot erstellt. Im nächsten Schritt werden Sie Benutzerbefehle verwalten und Ihren Bot zur Durchführung von Aktionen veranlassen, wie z. B. zum Senden von Nachrichten.

      Schritt 3 — Verwendung Ihres ersten Benutzerbefehls

      In diesem Schritt erstellen Sie einen Bot, der Benutzerbefehle handhaben kann. Sie werden Ihren ersten Befehl (ping) implementieren, der mit "pong" und der Zeit antworten wird, die zum Antworten auf den Befehl benötigt wurde.

      Zunächst müssen Sie alle Nachrichten erkennen und empfangen, die Benutzer senden, damit Sie Befehle verarbeiten können. Mit der Methode on auf dem Discord-Client wird Ihnen Discord eine Benachrichtigung zu neuen Ereignissen senden. Die Methode on hat zwei Argumente: den Namen eines Ereignisses, auf das gewartet wird, und eine Funktion, die jedes Mal ausgeführt wird, wenn das Ereignis eintritt. Bei dieser Methode können Sie auf das Ereignis message warten – es wird jedes Mal eintreten, wenn eine Nachricht an eine Gilde gesendet wird, in der der Bot die Berechtigung zum Anzeigen von Nachrichten hat. Lassen Sie uns daher eine Funktion erstellen, die bei jeder Übermittlung einer Nachricht ausgeführt wird, um Befehle zu verarbeiten.

      Öffnen Sie zunächst Ihre Datei:

      Fügen Sie den folgenden Code zur Datei hinzu:

      index.js

      ...
      const client = new Discord.Client();
      
      
      client.on("message", function(message) { 
                                               
      });                                      
      
      client.login(config.BOT_TOKEN);
      

      Diese Funktion, die beim Ereignis message ausgeführt wird, nutzt message als Parameter. message wird den Wert einer Discord.js message-Instanz haben, die Informationen über die gesendete Nachricht und Methoden enthält, um dem Bot beim Antworten zu helfen.

      Fügen Sie nun Ihrer Befehlsverarbeitungsfunktion die folgende Codezeile hinzu:

      index.js

      ...
      client.on("message", function(message) {
        if (message.author.bot) return;
      });
      ...
      

      Diese Zeile prüft, ob der Autor der Nachricht ein Bot ist; wenn ja, wird die Verarbeitung des Befehls gestoppt. Dies ist wichtig, da Sie Nachrichten von Bots im Allgemeinen weder bearbeiten noch beantworten möchten. Bots müssen oder wollen unseren Bot in der Regel nicht verwenden, sodass ein Ignorieren ihrer Nachrichten Rechenleistung spart und unbeabsichtigte Antworten verhindert.

      Jetzt schreiben Sie einen Befehlshandler. Um das zu erreichen, ist es hilfreich, das übliche Format eines Discord-Befehls zu verstehen. In der Regel enthält die Struktur eines Discord-Befehls drei Teile in der folgenden Reihenfolge: ein Präfix, einen Befehlsnamen und (manchmal) Befehlsargumente.

      Abbildung eines typischen Discord-Befehls, der

      • Präfix: Das Präfix kann alles sein, ist aber in der Regel eine Interpunktion oder abstrakte Phrase, die normalerweise nicht am Anfang einer Nachricht stehen würde. Das bedeutet, dass bei Eingabe des Präfix am Anfang der Nachricht der Bot weiß, dass der Befehl von einem Bot verarbeitet werden soll.

      • Befehlsname: Der Name des Befehls, den der Benutzer verwenden möchte. Das bedeutet, dass der Bot mehrere Befehle mit unterschiedlicher Funktionalität unterstützen kann und Benutzer durch Angabe eines anderen Befehlsnamens zwischen ihnen wählen können.

      • Argumente: Wenn der Befehl ggf. zusätzliche Informationen vom Benutzer benötigt oder verwendet, kann der Benutzer nach dem Befehlsnamen Argumente angeben, wobei jedes Argument durch ein Leerzeichen getrennt wird.

      Anmerkung: Es gibt keine zwingende Befehlsstruktur; Bots können Befehle verarbeiten, wie sie wollen. Die hier dargestellte Struktur ist jedoch eine effiziente Struktur, die eine überwiegende Mehrheit der Bots verwendet.

      Um mit der Erstellung eines Befehlsparsers zu beginnen, der dieses Format handhabt, fügen Sie der Nachrichtenverarbeitungsfunktion folgende Codezeilen hinzu:

      index.js

      ...
      const prefix = "!";
      
      client.on("message", function(message) {
        if (message.author.bot) return;
        if (!message.content.startsWith(prefix)) return;
      });
      ...
      

      Sie fügen die erste Codezeile hinzu, um den Wert "!" der Konstanten prefix zuzuweisen, die Sie als Präfix des Bots nutzen werden.

      Die zweite Codezeile, die Sie hinzufügen, prüft, ob der Inhalt der Nachricht, die der Bot verarbeitet, mit dem von Ihnen festgelegten Präfix beginnt; wenn nicht, wird die Weiterverarbeitung der Nachricht gestoppt.

      Jetzt müssen Sie den Rest der Nachricht in einen Befehlsnamen und jegliche Argumente konvertieren, die in der Nachricht vorhanden sind. Fügen Sie die folgenden hervorgehobenen Zeilen hinzu:

      index.js

      ...
      client.on("message", function(message) {
        if (message.author.bot) return;
        if (!message.content.startsWith(prefix)) return;
      
        const commandBody = message.content.slice(prefix.length);
        const args = commandBody.split(' ');
        const command = args.shift().toLowerCase();
      });
      ...
      

      Sie verwenden hier die erste Zeile, um das Präfix aus dem Nachrichteninhalt zu entfernen und das Ergebnis der Konstanten commandBody zuzuweisen. Dies ist notwendig, da Sie das Präfix nicht in den analysierten Befehlsnamen einfügen möchten.

      Die zweite Zeile nimmt die Nachricht mit dem entfernten Präfix und wendet die split-Methode darauf an, wobei ein Leerzeichen als Trennzeichen dient. Dadurch wird eine Aufspaltung in eine Gruppe von untergeordneten Zeichenfolgen vorgenommen, wobei bei jedem Leerzeichen eine Trennung vorgenommen wird. So entsteht ein Array, das den Befehlsnamen und dann (wenn in der Nachricht enthalten) Argumente beinhaltet. Sie weisen dieses Array der Konstanten args zu.

      Die dritte Zeile entfernt das erste Element aus dem Array args (was der bereitgestellte Befehlsname sein wird), konvertiert es in Kleinbuchstaben und weist es dann der Konstanten command zu. Dadurch können Sie den Befehlsnamen isolieren und nur Argumente im Array belassen. Außerdem verwenden Sie die Methode toLowerCase, da bei Befehlen in Discord-Bots typischerweise nicht zwischen Groß-/Kleinschreibung unterschieden wird.

      Sie haben die Erstellung eines Befehlsparsers, die Implementierung eines erforderlichen Präfix und das Erhalten des Befehlsnamens und der Argumente von Nachrichten abgeschlossen. Sie werden nun den Code für die spezifischen Befehle implementieren und erstellen.

      Fügen Sie folgenden Code hinzu, um den ping-Befehl zu implementieren:

      index.js

      ...
        const args = commandBody.split(' ');
        const command = args.shift().toLowerCase();
      
        if (command === "ping") {
                                 
        }                        
      });
      ...
      

      Diese if-Anweisung prüft, ob der analysierte Befehlsname (der der Konstanten command zugewiesen ist) mit "ping" übereinstimmt. Wenn ja, heißt das, dass der Benutzer den Befehl "ping" verwenden möchte. Sie werden den Code für den spezifischen Befehl im if-Anweisungsblock verschachteln. Sie werden dieses Muster für andere Befehle, die Sie implementieren möchten, wiederholen.

      Jetzt können Sie den Code für den Befehl "ping" implementieren:

      index.js

      ...
        if (command === "ping") {
          const timeTaken = Date.now() - message.createdTimestamp;
          message.reply(`Pong! This message had a latency of ${timeTaken}ms.`);
        }
      ...
      

      Speichern und schließen Sie Ihre Datei.

      Sie fügen den Befehlsblock "ping" hinzu, der die Differenz zwischen der aktuellen Zeit (ermittelt durch Anwendung der Methode now auf das Objekt Date) und dem Zeitstempel, als die Nachricht erstellt wurde, berechnet (in Millisekunden). Dadurch wird berechnet, wie lang die Verarbeitung der Nachricht und das "ping" des Bots benötigt haben.

      Die zweite Zeile reagiert auf den Befehl des Benutzers mit der reply-Methode in der Konstanten message. Die reply-Methode pingt (wodurch der Benutzer benachrichtigt und die Nachricht für den angegebenen Benutzer hervorgehoben wird) den Benutzer an, der den Befehl aufgerufen hat, gefolgt von dem Inhalt, der als erstes Argument der Methode angegeben wurde. Sie stellen ein template literal bereit, das eine Nachricht und den errechneten Ping als Antwort enthält, die die reply-Methode verwenden wird.

      Damit ist die Implementierung des Befehls "ping" abgeschlossen.

      Führen Sie Ihren Bot mit dem folgenden Befehl aus (im selben Ordner wie index.js):

      Sie können nun den Befehl "! ping" in jedem Kanal nutzen, den der Bot anzeigen und in dem der Bot Nachrichten senden kann; dabei kommt es zu einer Antwort.

      Abbildung von Bot, der in Discord auf

      Sie haben nun erfolgreich einen Bot erstellt, der Benutzerbefehle handhaben kann, und Ihren ersten Befehl implementiert. Im nächsten Schritt werden Sie Ihren Bot weiterentwickeln, indem Sie einen sum-Befehl implementieren.

      Schritt 4 — Implementieren des sum-Befehls

      Jetzt werden Sie Ihr Programm durch Implementieren des "! sum"-Befehls erweitern. Der Befehl nimmt eine beliebige Anzahl von Argumenten an und fügt sie zusammen, bevor die Summe aller Argumente an den Benutzer zurückgegegen wird.

      Wenn Ihr Discord-Bot noch ausgeführt wird, können Sie den Prozess mit Strg+C anhalten.

      Öffnen Sie erneut Ihre index.js-Datei:

      Um mit der Implementierung des "! sum"-Befehls zu beginnen, werden Sie einen else-if-Block verwenden. Nach der Prüfung des ping-Befehlsnamens wird geprüft, ob der Befehlsname gleich "sum" ist. Wir verwenden einen else-if-Block, da nur ein Befehl auf einmal verarbeitet wird; wenn das Programm dem Befehlsnamen "ping" entspricht, muss also nicht auf den Befehl "sum" geprüft werden. Fügen Sie in Ihrer Datei die folgenden hervorgehobenen Zeilen hinzu:

      index.js

      ...
        if (command === "ping") {
          const timeTaken = Date.now() - message.createdTimestamp;
          message.reply(`Ping! This message had a latency of ${timeTaken}ms.`);
        }
      
        else if (command === "sum") {
                                     
        }                            
      });
      ...
      

      Sie können mit der Implementierung des Codes für den "sum"-Befehl beginnen. Der Code für den Befehl "sum" wird in den gerade erstellten else-if-Block eingebunden. Fügen Sie nun folgenden Code hinzu:

      index.js

      ...
        else if (command === "sum") {
          const numArgs = args.map(x => parseFloat(x));
          const sum = numArgs.reduce((counter, x) => counter += x);
          message.reply(`The sum of all the arguments you provided is ${sum}!`);
        }
      ...
      

      Sie verwenden die map-Methode in der Argumentenliste, um eine neue Liste zu erstellen, indem Sie die Funktion parseFloat auf jedes Element im Array args anwenden. Dadurch ensteht ein neues Array (das der Konstanten numArgs zugewiesen ist), in dem alle Elemente Zahlen anstelle von Zeichenfolgen sind. Das bedeutet, dass Sie durch Addieren die Summe der Zahlen ermitteln können.

      Die zweite Zeile wendet die reduce-Methode auf die Konstante numArgs an; so ist eine Funktion verfügbar, die die Summe aller Elemente in der Liste errechnet. Sie weisen die Summe aller Elemente in numArgs der Konstanten sum zu.

      Dann wenden Sie die reply-Methode auf das Nachrichtenobjekt an, um auf den Befehl des Benutzers mit einem template literal zu antworten, das die Summe aller Argumente enthält, die der Benutzer an den Bot sendet.

      Damit ist die Implementierung des Befehls "sum" abgeschlossen. Führen Sie Ihren Bot nun mit dem folgenden Befehl aus (im selben Ordner wie index.js):

      Sie können den Befehl "! sum" jetzt in jedem Kanal verwenden, den der Bot anzeigen und in dem er Nachrichten senden kann.

      Abbildung von Bot, der mit „Die Summe aller von Ihnen angegebenen Argumente ist 6!“ auf

      Im Folgenden finden Sie eine fertige Version des index.js-Bot-Skripts:

      index.js

      const Discord = require("discord.js");
      const config = require("./config.json");
      
      const client = new Discord.Client();
      
      const prefix = "!";
      
      client.on("message", function(message) {
        if (message.author.bot) return;
        if (!message.content.startsWith(prefix)) return;
      
        const commandBody = message.content.slice(prefix.length);
        const args = commandBody.split(' ');
        const command = args.shift().toLowerCase();
      
        if (command === "ping") {
          const timeTaken = Date.now() - message.createdTimestamp;
          message.reply(`Pong! This message had a latency of ${timeTaken}ms.`);
        }
      
        else if (command === "sum") {
          const numArgs = args.map(x => parseFloat(x));
          const sum = numArgs.reduce((counter, x) => counter += x);
          message.reply(`The sum of all the arguments you provided is ${sum}!`);
        }
      });
      
      client.login(config.BOT_TOKEN);
      

      In diesem Schritt haben Sie Ihren Discord-Bot durch Implementieren des sum-Befehls weiterentwickelt.

      Zusammenfassung

      Sie haben einen Discord-Bot implementiert, der verschiedene Benutzerbefehle und Befehlsargumente handhaben kann. Wenn Sie Ihren Bot erweitern möchten, können Sie ggf. weitere Befehle implementieren oder weitere Bestandteile der Discord-API zur Erstellung eines leistungsfähigen Discord-Bots testen. Konsultieren Sie die Discord.js-Dokumentation oder Discord-API-Dokumentation, um mehr über die Discord-API zu erfahren.

      Bei der Erstellung von Discord-Bots müssen Sie stets die allgemeinen Geschäftsbedingungen der Discord-API im Auge behalten; darin wird umrissen, wie Entwickler die Discord-API verwenden müssen. Außerdem können Sie diesen Satz an Leitfäden lesen, um einen Discord-Bot optimal zu implementieren und Tipps zur Gestaltung von Discord-Bots zu erhalten. Wenn Sie mehr über Node.js erfahren möchten, lesen Sie unsere Serie zum Codieren in Node.js.



      Source link