Мы часто создаем веб-приложений, в которых требуется доставить большие наборы записей данных с удаленного сервера, API или базы данных. Например, если вы создаете платежную систему, она может доставлять тысячи транзакций. Если это приложение социальной сети, оно может отображать множество комментариев, профилей и действий пользователей. В любом случае существует несколько способов представления данных в такой форме, которая не перегрузит конечного пользователя приложения.
Один из методов работы с большими наборами данных — это разбивка на страницы. Разбивка на страницы эффективно работает, когда вы заранее знаете размер набора данных (общее количество записей в наборе данных). Вам нужно загрузить только требуемую часть данных из набора в зависимости от взаимодействия конечного пользователя с элементом управления разбивкой на страницы. Эта методика используется для отображения результатов поиска в поисковике Google.
В этом учебном модуле вы научитесь создавать специальный компонент разбивки на страницы с помощью React для разбивки на страницы больших наборов данных. Мы построим разбитое на страницы представление всех стран мира, используя набор данных с известным размером.
Вот демонстрация того, что вы сделаете в этом учебном модуле:
Для данного обучающего руководства вам потребуется следующее:
npm < 5.2
, возможно, вам потребуется установить create-react-app
как глобальную зависимость.Этот учебный модуль был проверен с использованием Node v14.2.0, npm
v6.14.4, react
v16.13.1 и react-scripts
v3.4.1.
Создайте новое приложение React, используя команду create-react-app
. Вы можете назвать приложение как угодно, но в этом учебном модуле мы присвоим ему имя react-pagination
:
Затем мы установим зависимости, необходимые для вашего приложения. Для начала используйте окно терминала, чтобы перейти в каталог проекта:
Выполните следующую команду для установки требуемых зависимостей:
При этом будут установлены элементы bootstrap
, prop-types
, react-flags
, countries-api
и node-sass
.
Вы установили пакет bootstrap
как зависимость для вашего приложения, поскольку вам потребуются некоторые стили, доступные по умолчанию. Также вы будете использовать стили компонента Bootstrap pagination
.
Чтобы включить Bootstrap в приложение, отредактируйте файл src/index.js
:
Добавьте следующую строку перед другими выражениями import
:
Теперь в вашем приложении будут доступны стили Bootstrap.
Также вы установили react-flags
как зависимость для вашего приложения. Чтобы получить доступ к иконкам флагов из вашего приложения, вам потребуется скопировать изображения иконок в каталог public
вашего приложения.
Создайте каталог img
в вашем каталоге public
:
Скопируйте файлы изображения из flags
в img
:
Это обеспечивает создание копии всех изображений react-flag
в вашем приложении.
Теперь мы добавили некоторые зависимости и можем запустить приложение, выполнив следующую команду с npm
в каталоге проекта react-pagination
:
Теперь вы запустили приложение и можете начинать разработку. Обратите внимание, что для вас открыта вкладка браузера с функцией перезагрузки в реальном времени, что позволит сохранять синхронизацию с приложением в процессе разработки.
Представление приложения должно выглядеть как на следующем снимке экрана:
Теперь вы готовы начать создание компонентов.
CountryCard
На этом шаге мы создадим компонент CountryCard
. Компонент CountryCard
выполняет рендеринг имени, региона и флага определенной страны.
Для начала создадим каталог components
в каталоге src
:
Затем создадим новый файл CountryCard.js
в каталоге src/components
:
Добавим в него следующий блок кода:
Для компонента CountryCard
требуется объект country
, содержащий данные о стране, которые будут выводиться. Как можно увидеть в списке propTypes
для компонента CountryCard
, объект country
должен содержать следующие данные:
cca2
— 2-значный код страныregion
— регион страны (например, «Африка»)name.common
— общее название страны (например, «Нигерия»)Вот образец объекта страны:
Обратите внимание на рендеринг флага страны с использованием пакета react-flags
. Вы можете посмотреть документацию react-flags
, чтобы узнать больше о требуемых объектах и использовании пакета.
Теперь вы заполнили отдельный компонент CountryCard
. В конечном итоге вы будете использовать компоненты CountryCard
несколько раз, чтобы выводить в приложении разные флаги и информацию о разных странах.
Pagination
На этом шаге мы создадим компонент Pagination
. Компонент Pagination
содержит логику построения, рендеринга и переключения страниц в элементе управления разбивкой на страницы.
Создайте новый файл Pagination.js
в каталоге src/components
:
Добавим в него следующий блок кода:
Компонент Pagination
может принимать четыре специальных объекта, указанные в объекте propTypes
.
onPageChanged
— это функция, вызываемая с данными по текущему состоянию разбивки на страницы, только в случае изменения текущей страницы.totalRecords
указывает общее количество записей, которое требуется разбить на страницы. Это значение является обязательным.pageLimit
указывает количество отображаемых записей на каждой странице. Если этот параметр не указан, по умолчанию используется значение 30
, определенное в constructor()
.pageNeighbours
указывает количество номеров дополнительных страниц, отображаемое на каждой стороне текущей страницы. Минимальное значение 0
, максимальное значение 2
. Если параметр не определен, по умолчанию используется значение 0
, определенное в constructor()
.На следующем изображении показан эффект различных значений объекта pageNeighbours
:
В функции constructor()
мы рассчитываем общее количество страниц следующим образом:
Обратите внимание, что здесь мы используем Math.ceil()
, чтобы получить целое значение общего количества страниц. При этом также обеспечивается регистрация лишних записей на последней странице, особенно в случаях, когда количество лишних записей меньше количества записей, отображаемого на странице.
Наконец, вы инициализировали состояние с установленным для свойства currentPage
значением 1
. Это свойство состояния нужно вам для внутреннего отслеживания текущей активной страницы.
Затем вы создадите метод для генерирования номеров страниц.
После import
, но до класса Pagination
нужно добавить следующие константы и функцию range
:
В классе Pagination
после функции constructor
нужно добавить следующий метод fetchPageNumbers
:
Вначале вы определите две константы: LEFT_PAGE
и RIGHT_PAGE
. Эти константы будут использоваться для указания точек расположения элементов управления для перехода на следующую страницу слева и справа соответственно.
Также вы определили вспомогательную функцию range()
, которая поможет вам генерировать диапазоны чисел.
Примечание. Если вы используете в проекте библиотеку утилит, например, Lodash, вы можете использовать функцию _.range()
, предоставляемую Lodash. В следующем блоке кода показаны отличия между функцией range()
, которую мы только что определили, и функцией от Lodash:
Далее мы определили метод fetchPageNumbers()
в классе Pagination
. Этот метод отвечает за выполнение базовой логики генерирования номеров страниц для отображения элементом управления разбивкой на страницы. Нам нужно, чтобы первая и последняя страницы всегда были видны.
Вначале мы определили две переменные. totalNumbers
представляет общее количество страниц, показываемое на элементе управления. totalBlocks
показывает общее количество страниц плюс два дополнительных блока для индикаторов страниц слева и справа.
Если значение totalPages
не больше, чем totalBlocks
, возвращается диапазон чисел от 1
до totalPages
. В ином случае возвращается массив номеров страниц с LEFT_PAGE
и RIGHT_PAGE
в точках, где можно перейти на страницу слева или справа.
Обратите внимание, что элемент управления разбивкой на страницы обеспечивает постоянную видимость первой и последней страниц. Элементы управления переходом на левую и правую страницы отображаются внутри.
Теперь мы добавим метод render()
, чтобы выполнить рендеринг элемента управления разбивкой на страницы.
В классе Pagination
после функции constructor
и метода fetchPageNumbers
нужно добавить следующий метод render
:
Здесь мы генерируем массив
номеров страниц, вызывая метод fetchPageNumbers()
, который мы создали ранее. Затем выполняется рендеринг каждого номера страницы с использованием Array.prototype.map()
. Обратите внимание, что необходимо регистрировать обработчики событий нажатия для каждого отображаемого номера страницы, чтобы обеспечить обработку нажатий.
Также следует отметить, что элемент управления разбивкой на страницы не отображается, если объект totalRecords
не был передан в компонент Pagination
надлежащим образом или в случаях, когда имеется только 1
страница.
В заключение мы определим методы обработчика событий.
Добавьте следующее в классе Pagination
после функции constructor
, метода fetchPageNumbers
и метода render
:
Вы определили метод gotoPage()
, который изменяет состояние и устанавливает указанную страницу как currentPage
. Он гарантирует, что аргумент page
имеет значение не менее 1
и не более общего количества страниц. В завершение он вызывает функцию onPageChanged()
, которая была передана как объект, с данными, указывающими новое состояние разбивки на страницы.
При монтировании компонента мы переходим на первую страницу, вызывая this.gotoPage(1)
, как показано в методе жизненного цикла componentDidMount()
.
Обратите внимание на использовании (this.pageNeighbours * 2)
в handleMoveLeft()
и handleMoveRight()
для прокрутки номеров страниц влево и вправо соответственно в зависимости от текущего номера страницы.
Вот демонстрация взаимодействия при движении слева направо.
Мы закончили работу над компонентом Pagination
. Теперь пользователи смогут использовать элементы навигации этого компонента для отображения разных страниц с флагами.
App
Обратите внимание, что теперь у нас имеются компоненты CountryCard
и Pagination
, и мы можем использовать их в нашем компоненте App
.
Измените файл App.js
в каталоге src
:
Замените содержимое файла App.js
следующими строками кода:
Здесь мы инициализируем состояние компонента App
, используя следующие атрибуты:
allCountries
— это массив всех стран в вашем приложении. Инициализируется как пустой массив ([]
).currentCountries
— это массив всех стран, отображаемых на активной странице. Инициализируется как пустой массив ([]
).currentPage
— номер активной страницы. Инициализируется как null
.totalPages
— общее количество страниц со всеми записями стран. Инициализируется как null
.Затем в методе жизненного цикла componentDidMount()
мы доставляем все страны мира, используя пакет countries-api
посредством вызова Countries.findAll()
. Затем мы обновляем состояние приложения, устанавливая все страны мира как содержимое allCountries
. Вы можете посмотреть [документацию по countries-api
], countries-apiчтобы узнать больше о пакете.
В заключение мы определили метод onPageChanged()
, который будет вызываться при каждом переходе на новую страницу из элемента управления разбивкой на страницы. Этот метод будет передаваться в объект onPageChanged
компонента Pagination
.
При использовании этого метода следует обратить внимание на две строки. Вот первая из этих строк:
Значение offset
указывает на начальный индекс для доставки записей для текущей страницы. Благодаря использованию (currentPage - 1)
коррекция основана на нулевом значении. Допустим, мы отображаем 25
записей на каждой странице, и вы просматриваете страницу 5
. Тогда значение коррекции
будет ((5 - 1) * 25 = 100)
.
Например, если вы доставляете записи по запросу из базы данных, этот образец запроса SQL покажет вам, как использовать данную коррекцию:
Поскольку мы не доставляем записи из базы данных или внешнего источника, нам нужен способ извлечь требуемое количество записей для отображения на текущей странице.
Вторая строка выглядит так:
Здесь мы использовали метод Array.prototype.slice()
для извлечения требуемого блока записей из массива allCountries
, передавая offset
как указатель начала блока и (offset + pageLimit)
как указатель конца блока.
Примечание. В этом учебном модуле мы не доставляли записи из внешнего источника. В реальном приложении записи обычно доставляются из базы данных или через API. Логику доставки записей можно разместить в методе onPageChanged()
компонента App
.
Допустим, вы используете вымышленную конечную точку API /api/countries?page={current_page}&limit={page_limit}
. В следующем блоке кода показано, как доставлять страны по запросу из API, используя пакет axios
HTTP:
Теперь вы можете закончить компонент App
, добавив метод render()
.
В классе App
после componentDidMount
и onPageChanged
нужно добавить следующий метод render
:
В методе render()
мы выполняем рендеринг общего количества стран, текущей страницы, общего количества страниц, элемента управления <Pagination>
и <CountryCard>
для каждой страны на текущей странице.
Обратите внимание, что вы передали ранее определенный метод onPageChanged()
в объект onPageChanged
элемента управления <Pagination>
. Это очень важно для регистрации изменений страниц из компонента Pagination
. Мы выводим 18
стран на одной странице.
Сейчас приложение выглядит, как показано на следующем снимке экрана:
Теперь у нас имеется компонент App
, позволяющий отображать различные компоненты CountryCard
и Pagination
, разделяющие содержимое на отдельные страницы. Далее мы рассмотрим применение стилей к нашему приложению.
Возможно вы заметили, что мы добавляли определенные специальные классы в ранее созданные компоненты. Давайте определим некоторые правила стилей для этих классов в файле src/App.scss
.
Файл App.scss
будет выглядеть, как следующий фрагмент кода:
Измените файл App.js
так, чтобы он ссылался на App.scss
, а не на App.css
.
Примечание. Для получения дополнительной информации ознакомьтесь с документацией по Create React App.
После добавления стилей приложение будет выглядеть, как показано на следующем снимке экрана:
Теперь у вас имеется полное приложение с дополнительными индивидуальными стилями. Вы можете использовать индивидуальные стили для изменения или расширения любых стилей по умолчанию, предоставляемых Bootstrap и другими библиотеками.
В этом учебном модуле мы создали специальный виджет разбивки на страницы в приложении React. Хотя в этом учебном модуле мы не вызывали API и не взаимодействовали с сервером баз данных, для вашего приложения может потребоваться такое взаимодействие. Описанный в этом учебном модуле подход не ограничивает ваши возможности, вы можете расширять его как угодно, чтобы решить стоящие перед вашим приложением задачи.
Полный исходный код этого учебного модуля можно найти в репозитории build-react-pagination-demo на GitHub. Также вы можете посмотреть работающую демонстрацию этого учебного модуля на Code Sandbox.
Если вы хотите узнать больше о React, почитайте нашу серию «Программирование на React.js» или посмотрите страницу тем React, где вы найдете упражнения и программные проекты.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!