One place for hosting & domains

      страницы

      Специальная разбивка на страницы с помощью React


      Введение

      Мы часто создаем веб-приложений, в которых требуется доставить большие наборы записей данных с удаленного сервера, API или базы данных. Например, если вы создаете платежную систему, она может доставлять тысячи транзакций. Если это приложение социальной сети, оно может отображать множество комментариев, профилей и действий пользователей. В любом случае существует несколько способов представления данных в такой форме, которая не перегрузит конечного пользователя приложения.

      Один из методов работы с большими наборами данных — это разбивка на страницы. Разбивка на страницы эффективно работает, когда вы заранее знаете размер набора данных (общее количество записей в наборе данных). Вам нужно загрузить только требуемую часть данных из набора в зависимости от взаимодействия конечного пользователя с элементом управления разбивкой на страницы. Эта методика используется для отображения результатов поиска в поисковике Google.

      В этом учебном модуле вы научитесь создавать специальный компонент разбивки на страницы с помощью React для разбивки на страницы больших наборов данных. Мы построим разбитое на страницы представление всех стран мира, используя набор данных с известным размером.

      Вот демонстрация того, что вы сделаете в этом учебном модуле:

      Снимок экрана демонстрационного приложения — показ стран мира

      Предварительные требования

      Для данного обучающего руководства вам потребуется следующее:

      • [Node], nodejsустановленный на вашем компьютере. Процедура установки описана в документе «Установка Node.js и создание локальной среды разработки».
      • Пакет командной строки [create-react-app][`create-react-app] создает базовый код для вашего приложения React. Если вы используете версиюnpm < 5.2, возможно, вам потребуется установитьcreate-react-app` как глобальную зависимость.
      • Наконец, в этом обучающем модуле предполагается, что вы уже знакомы с React. Если это не так, вы можете ознакомиться с серией «Программирование на React.js», чтобы узнать больше о React.

      Этот учебный модуль был проверен с использованием Node v14.2.0, npm v6.14.4, react v16.13.1 и react-scripts v3.4.1.

      Шаг 1 — Настройка проекта

      Создайте новое приложение React, используя команду create-react-app. Вы можете назвать приложение как угодно, но в этом учебном модуле мы присвоим ему имя react-pagination:

      • npx create-react-app react-pagination

      Затем мы установим зависимости, необходимые для вашего приложения. Для начала используйте окно терминала, чтобы перейти в каталог проекта:

      Выполните следующую команду для установки требуемых зависимостей:

      • 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

      При этом будут установлены элементы bootstrap, prop-types, react-flags, countries-api и node-sass.

      Вы установили пакет bootstrap как зависимость для вашего приложения, поскольку вам потребуются некоторые стили, доступные по умолчанию. Также вы будете использовать стили компонента Bootstrap pagination.

      Чтобы включить Bootstrap в приложение, отредактируйте файл src/index.js:

      Добавьте следующую строку перед другими выражениями import:

      src/index.js

      import "bootstrap/dist/css/bootstrap.min.css";
      

      Теперь в вашем приложении будут доступны стили Bootstrap.

      Также вы установили react-flags как зависимость для вашего приложения. Чтобы получить доступ к иконкам флагов из вашего приложения, вам потребуется скопировать изображения иконок в каталог public вашего приложения.

      Создайте каталог img в вашем каталоге public:

      Скопируйте файлы изображения из flags в img:

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

      Это обеспечивает создание копии всех изображений react-flag в вашем приложении.

      Теперь мы добавили некоторые зависимости и можем запустить приложение, выполнив следующую команду с npm в каталоге проекта react-pagination:

      Теперь вы запустили приложение и можете начинать разработку. Обратите внимание, что для вас открыта вкладка браузера с функцией перезагрузки в реальном времени, что позволит сохранять синхронизацию с приложением в процессе разработки.

      Представление приложения должно выглядеть как на следующем снимке экрана:

      Начальное представление — экран приветствия React

      Теперь вы готовы начать создание компонентов.

      Шаг 2 — Создание компонента CountryCard

      На этом шаге мы создадим компонент CountryCard. Компонент CountryCard выполняет рендеринг имени, региона и флага определенной страны.

      Для начала создадим каталог components в каталоге src:

      Затем создадим новый файл CountryCard.js в каталоге src/components:

      • nano src/components/CountryCard.js

      Добавим в него следующий блок кода:

      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;
      

      Для компонента CountryCard требуется объект country, содержащий данные о стране, которые будут выводиться. Как можно увидеть в списке propTypes для компонента CountryCard, объект country должен содержать следующие данные:

      • cca2 — 2-значный код страны
      • region — регион страны (например, «Африка»)
      • name.common — общее название страны (например, «Нигерия»)

      Вот образец объекта страны:

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

      Обратите внимание на рендеринг флага страны с использованием пакета react-flags. Вы можете посмотреть документацию react-flags, чтобы узнать больше о требуемых объектах и использовании пакета.

      Теперь вы заполнили отдельный компонент CountryCard. В конечном итоге вы будете использовать компоненты CountryCard несколько раз, чтобы выводить в приложении разные флаги и информацию о разных странах.

      На этом шаге мы создадим компонент Pagination. Компонент Pagination содержит логику построения, рендеринга и переключения страниц в элементе управления разбивкой на страницы.

      Создайте новый файл Pagination.js в каталоге src/components:

      • nano src/components/Pagination.js

      Добавим в него следующий блок кода:

      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;
      

      Компонент Pagination может принимать четыре специальных объекта, указанные в объекте propTypes.

      • onPageChanged — это функция, вызываемая с данными по текущему состоянию разбивки на страницы, только в случае изменения текущей страницы.
      • totalRecords указывает общее количество записей, которое требуется разбить на страницы. Это значение является обязательным.
      • pageLimit указывает количество отображаемых записей на каждой странице. Если этот параметр не указан, по умолчанию используется значение 30, определенное в constructor().
      • pageNeighbours указывает количество номеров дополнительных страниц, отображаемое на каждой стороне текущей страницы. Минимальное значение 0, максимальное значение 2. Если параметр не определен, по умолчанию используется значение 0, определенное в constructor().

      На следующем изображении показан эффект различных значений объекта pageNeighbours:

      Иллюстрация соседних страниц

      В функции constructor() мы рассчитываем общее количество страниц следующим образом:

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

      Обратите внимание, что здесь мы используем Math.ceil(), чтобы получить целое значение общего количества страниц. При этом также обеспечивается регистрация лишних записей на последней странице, особенно в случаях, когда количество лишних записей меньше количества записей, отображаемого на странице.

      Наконец, вы инициализировали состояние с установленным для свойства currentPage значением 1. Это свойство состояния нужно вам для внутреннего отслеживания текущей активной страницы.

      Затем вы создадите метод для генерирования номеров страниц.

      После import, но до класса Pagination нужно добавить следующие константы и функцию range:

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

      В классе Pagination после функции constructor нужно добавить следующий метод fetchPageNumbers:

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

      Вначале вы определите две константы: LEFT_PAGE и RIGHT_PAGE. Эти константы будут использоваться для указания точек расположения элементов управления для перехода на следующую страницу слева и справа соответственно.

      Также вы определили вспомогательную функцию range(), которая поможет вам генерировать диапазоны чисел.

      Примечание. Если вы используете в проекте библиотеку утилит, например, Lodash, вы можете использовать функцию _.range(), предоставляемую Lodash. В следующем блоке кода показаны отличия между функцией range(), которую мы только что определили, и функцией от Lodash:

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

      Далее мы определили метод fetchPageNumbers() в классе Pagination. Этот метод отвечает за выполнение базовой логики генерирования номеров страниц для отображения элементом управления разбивкой на страницы. Нам нужно, чтобы первая и последняя страницы всегда были видны.

      Вначале мы определили две переменные. totalNumbers представляет общее количество страниц, показываемое на элементе управления. totalBlocks показывает общее количество страниц плюс два дополнительных блока для индикаторов страниц слева и справа.

      Если значение totalPages не больше, чем totalBlocks, возвращается диапазон чисел от 1 до totalPages. В ином случае возвращается массив номеров страниц с LEFT_PAGE и RIGHT_PAGE в точках, где можно перейти на страницу слева или справа.

      Обратите внимание, что элемент управления разбивкой на страницы обеспечивает постоянную видимость первой и последней страниц. Элементы управления переходом на левую и правую страницы отображаются внутри.

      Теперь мы добавим метод render(), чтобы выполнить рендеринг элемента управления разбивкой на страницы.

      В классе Pagination после функции constructor и метода fetchPageNumbers нужно добавить следующий метод render:

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

      Здесь мы генерируем массив номеров страниц, вызывая метод fetchPageNumbers(), который мы создали ранее. Затем выполняется рендеринг каждого номера страницы с использованием Array.prototype.map(). Обратите внимание, что необходимо регистрировать обработчики событий нажатия для каждого отображаемого номера страницы, чтобы обеспечить обработку нажатий.

      Также следует отметить, что элемент управления разбивкой на страницы не отображается, если объект totalRecords не был передан в компонент Pagination надлежащим образом или в случаях, когда имеется только 1 страница.

      В заключение мы определим методы обработчика событий.

      Добавьте следующее в классе Pagination после функции constructor, метода fetchPageNumbers и метода render:

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

      Вы определили метод gotoPage(), который изменяет состояние и устанавливает указанную страницу как currentPage. Он гарантирует, что аргумент page имеет значение не менее 1 и не более общего количества страниц. В завершение он вызывает функцию onPageChanged(), которая была передана как объект, с данными, указывающими новое состояние разбивки на страницы.

      При монтировании компонента мы переходим на первую страницу, вызывая this.gotoPage(1), как показано в методе жизненного цикла componentDidMount().

      Обратите внимание на использовании (this.pageNeighbours * 2) в handleMoveLeft() и handleMoveRight() для прокрутки номеров страниц влево и вправо соответственно в зависимости от текущего номера страницы.

      Вот демонстрация взаимодействия при движении слева направо.

      Движение слева направо при взаимодействии

      Мы закончили работу над компонентом Pagination. Теперь пользователи смогут использовать элементы навигации этого компонента для отображения разных страниц с флагами.

      Шаг 4 — Построение компонента App

      Обратите внимание, что теперь у нас имеются компоненты CountryCard и Pagination, и мы можем использовать их в нашем компоненте App.

      Измените файл App.js в каталоге src:

      Замените содержимое файла App.js следующими строками кода:

      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;
      

      Здесь мы инициализируем состояние компонента App, используя следующие атрибуты:

      • allCountries — это массив всех стран в вашем приложении. Инициализируется как пустой массив ([]).
      • currentCountries — это массив всех стран, отображаемых на активной странице. Инициализируется как пустой массив ([]).
      • currentPage — номер активной страницы. Инициализируется как null.
      • totalPages — общее количество страниц со всеми записями стран. Инициализируется как null.

      Затем в методе жизненного цикла componentDidMount() мы доставляем все страны мира, используя пакет countries-api посредством вызова Countries.findAll(). Затем мы обновляем состояние приложения, устанавливая все страны мира как содержимое allCountries. Вы можете посмотреть [документацию по countries-api], countries-apiчтобы узнать больше о пакете.

      В заключение мы определили метод onPageChanged(), который будет вызываться при каждом переходе на новую страницу из элемента управления разбивкой на страницы. Этот метод будет передаваться в объект onPageChanged компонента Pagination.

      При использовании этого метода следует обратить внимание на две строки. Вот первая из этих строк:

      const offset = (currentPage - 1) * pageLimit;
      

      Значение offset указывает на начальный индекс для доставки записей для текущей страницы. Благодаря использованию (currentPage - 1) коррекция основана на нулевом значении. Допустим, мы отображаем 25 записей на каждой странице, и вы просматриваете страницу 5. Тогда значение коррекции будет ((5 - 1) * 25 = 100).

      Например, если вы доставляете записи по запросу из базы данных, этот образец запроса SQL покажет вам, как использовать данную коррекцию:

      SELECT * FROM `countries` LIMIT 100, 25
      

      Поскольку мы не доставляем записи из базы данных или внешнего источника, нам нужен способ извлечь требуемое количество записей для отображения на текущей странице.

      Вторая строка выглядит так:

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

      Здесь мы использовали метод Array.prototype.slice() для извлечения требуемого блока записей из массива allCountries, передавая offset как указатель начала блока и (offset + pageLimit) как указатель конца блока.

      Примечание. В этом учебном модуле мы не доставляли записи из внешнего источника. В реальном приложении записи обычно доставляются из базы данных или через API. Логику доставки записей можно разместить в методе onPageChanged() компонента App.

      Допустим, вы используете вымышленную конечную точку API /api/countries?page={current_page}&limit={page_limit}. В следующем блоке кода показано, как доставлять страны по запросу из API, используя пакет axios HTTP:

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

      Теперь вы можете закончить компонент App, добавив метод render().

      В классе App после componentDidMount и onPageChanged нужно добавить следующий метод render:

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

      В методе render() мы выполняем рендеринг общего количества стран, текущей страницы, общего количества страниц, элемента управления <Pagination> и <CountryCard> для каждой страны на текущей странице.

      Обратите внимание, что вы передали ранее определенный метод onPageChanged() в объект onPageChanged элемента управления <Pagination>. Это очень важно для регистрации изменений страниц из компонента Pagination. Мы выводим 18 стран на одной странице.

      Сейчас приложение выглядит, как показано на следующем снимке экрана:

      Снимок экрана приложения с 248 указанными странами и номерами страниц сверху и до конца каждой страницы

      Теперь у нас имеется компонент App, позволяющий отображать различные компоненты CountryCard и Pagination, разделяющие содержимое на отдельные страницы. Далее мы рассмотрим применение стилей к нашему приложению.

      Шаг 5 — Добавление специальных стилей

      Возможно вы заметили, что мы добавляли определенные специальные классы в ранее созданные компоненты. Давайте определим некоторые правила стилей для этих классов в файле src/App.scss.

      Файл App.scss будет выглядеть, как следующий фрагмент кода:

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

      Измените файл App.js так, чтобы он ссылался на App.scss, а не на App.css.

      Примечание. Для получения дополнительной информации ознакомьтесь с документацией по 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';
      

      После добавления стилей приложение будет выглядеть, как показано на следующем снимке экрана:

      Снимок экрана приложения, страница 1 из 14, со стилями

      Теперь у вас имеется полное приложение с дополнительными индивидуальными стилями. Вы можете использовать индивидуальные стили для изменения или расширения любых стилей по умолчанию, предоставляемых Bootstrap и другими библиотеками.

      Заключение

      В этом учебном модуле мы создали специальный виджет разбивки на страницы в приложении React. Хотя в этом учебном модуле мы не вызывали API и не взаимодействовали с сервером баз данных, для вашего приложения может потребоваться такое взаимодействие. Описанный в этом учебном модуле подход не ограничивает ваши возможности, вы можете расширять его как угодно, чтобы решить стоящие перед вашим приложением задачи.

      Полный исходный код этого учебного модуля можно найти в репозитории build-react-pagination-demo на GitHub. Также вы можете посмотреть работающую демонстрацию этого учебного модуля на Code Sandbox.

      Если вы хотите узнать больше о React, почитайте нашу серию «Программирование на React.js» или посмотрите страницу тем React, где вы найдете упражнения и программные проекты.



      Source link