Reactでカスタムページネーションを構築する方法
序章
多くの場合、リモートサーバー、API、またはデータベースから大量のデータレコードをフェッチする必要があるWebアプリケーションの構築に関与します。 たとえば、支払いシステムを構築している場合、何千ものトランザクションをフェッチしている可能性があります。 ソーシャルメディアアプリの場合、多くのユーザーコメント、プロファイル、またはアクティビティを取得している可能性があります。 いずれの場合でも、アプリを操作するエンドユーザーを圧倒しない方法でデータを表示するためのソリューションがいくつかあります。
大規模なデータセットを処理する1つの方法は、paginationを使用することです。 データセットのサイズ(データセット内のレコードの総数)が事前にわかっている場合、ページネーションは効果的に機能します。 次に、エンドユーザーとページネーションコントロールの相互作用に基づいて、データセット全体から必要なデータのチャンクのみをロードします。 これは、Google検索で検索結果を表示するために使用される手法です。
このチュートリアルでは、大規模なデータセットをページ付けするためにReactを使用してカスタムページ付けコンポーネントを構築する方法を学習します。 世界の国々のページ化されたビュー(既知のサイズのデータセット)を作成します。
これは、このチュートリアルで構築するもののデモです。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- ノードがマシンにインストールされています。 手順は、Node.jsをインストールしてローカル開発環境を作成する方法にあります。
- create-react-app コマンドラインパッケージを使用して、Reactアプリのボイラープレートコードを作成します。
npm < 5.2
を使用している場合は、グローバル依存関係としてcreate-react-app
をインストールする必要がある場合があります。 - 最後に、このチュートリアルは、あなたがすでにReactに精通していることを前提としています。 そうでない場合は、 React.jsのコーディング方法シリーズをチェックして、Reactの詳細を確認してください。
このチュートリアルは、ノードv14.2.0、npm
v6.14.4、react
v16.13.1、およびreact-scripts
v3.4.1で検証されました。
ステップ1—プロジェクトの設定
create-react-app
コマンドを使用して新しいReactアプリケーションを起動します。 アプリケーションには任意の名前を付けることができますが、このチュートリアルではreact-pagination
という名前を付けます。
npx create-react-app react-pagination
次に、アプリケーションに必要な依存関係をインストールします。 まず、ターミナルウィンドウを使用して、プロジェクトディレクトリに移動します。
cd react-pagination
次のコマンドを実行して、必要な依存関係をインストールします。
npm install [email protected] [email protected] [email protected] [email protected] [email protected]
これにより、bootstrap
、prop-types
、react-flags
、countries-api
、およびnode-sass
がインストールされます。
デフォルトのスタイルが必要になるため、アプリケーションの依存関係としてbootstrap
パッケージをインストールしました。 Bootstrappagination
コンポーネントのスタイルも使用します。
アプリケーションにブートストラップを含めるには、src/index.js
ファイルを編集します。
nano src/index.js
そして、他のimport
ステートメントの前に次の行を追加します。
src / index.js
import "bootstrap/dist/css/bootstrap.min.css";
これで、Bootstrapスタイリングがアプリケーション全体で利用できるようになります。
また、アプリケーションの依存関係としてreact-flags
をインストールしました。 アプリケーションからフラグアイコンにアクセスするには、アイコン画像をアプリケーションのpublic
ディレクトリにコピーする必要があります。
public
ディレクトリにimg
ディレクトリを作成します。
mkdir public/img
flags
の画像ファイルをimg
にコピーします。
cp -R node_modules/react-flags/vendor/flags public/img
これにより、すべてのreact-flag
イメージのコピーがアプリケーションに提供されます。
いくつかの依存関係を含めたので、react-pagination
プロジェクトディレクトリからnpm
を指定して次のコマンドを実行し、アプリケーションを起動します。
npm start
アプリケーションを開始したので、開発を開始できます。 ライブリロード機能を備えたブラウザタブが開いており、開発中にアプリケーションとの同期を維持していることに注意してください。
この時点で、アプリケーションビューは次のスクリーンショットのようになります。
これで、コンポーネントの作成を開始する準備が整いました。
ステップ2—CountryCard
コンポーネントを作成する
このステップでは、CountryCard
コンポーネントを作成します。 CountryCard
コンポーネントは、特定の国の名前、地域、および旗をレンダリングします。
まず、src
ディレクトリにcomponents
ディレクトリを作成しましょう。
mkdir src/components
次に、src/components
ディレクトリに新しいCountryCard.js
ファイルを作成します。
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
小道具が必要です。 CountryCard
コンポーネントのpropTypes
に見られるように、country
プロップオブジェクトには次のデータが含まれている必要があります。
cca2
-2桁の国コードregion
-国の地域(例:「アフリカ」)name.common
-国の一般名(例:「ナイジェリア」)
国オブジェクトのサンプルは次のとおりです。
{ cca2: "NG", region: "Africa", name: { common: "Nigeria" } }
また、react-flags
パッケージを使用して国旗をレンダリングする方法にも注目してください。 react-flagsのドキュメントをチェックして、必要な小道具とパッケージの使用方法の詳細を確認できます。
これで、個々のCountryCard
コンポーネントが完成しました。 最終的には、CountryCard
を複数回使用して、アプリケーションにさまざまなフラグと国情報を表示します。
ステップ3—Pagination
コンポーネントを作成する
このステップでは、Pagination
コンポーネントを作成します。 Pagination
コンポーネントには、ページネーションコントロールでページを作成、レンダリング、および切り替えるためのロジックが含まれています。
src/components
ディレクトリに新しいPagination.js
ファイルを作成します。
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
オブジェクトで指定されているように、4つの特別な小道具を取ることができます。
onPageChanged
は、現在のページが変更された場合にのみ、現在のページネーション状態のデータで呼び出される関数です。totalRecords
は、ページ付けされるレコードの総数を示します。 必須です。pageLimit
は、ページごとに表示されるレコードの数を示します。 指定しない場合、constructor()
で定義されているように、デフォルトで30
になります。pageNeighbours
は、現在のページの両側に表示される追加のページ番号の数を示します。 最小値は0
、最大値は2
です。 指定しない場合、constructor()
で定義されているように、デフォルトで0
になります。
次の画像は、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
の2つの定数を定義します。 これらの定数は、それぞれ左右に移動するためのページコントロールがあるポイントを示すために使用されます。
また、数値の範囲を生成するのに役立つヘルパーrange()
関数を定義しました。
注:プロジェクトで Lodash のようなユーティリティライブラリを使用する場合は、代わりにLodashが提供する_.range()
関数を使用できます。 次のコードスニペットは、先ほど定義したrange()
関数とLodashの関数の違いを示しています。
range(1, 5); // returns [1, 2, 3, 4, 5] _.range(1, 5); // returns [1, 2, 3, 4]
次に、Pagination
クラスでfetchPageNumbers()
メソッドを定義しました。 このメソッドは、ページネーションコントロールに表示されるページ番号を生成するためのコアロジックを処理します。 最初のページと最後のページを常に表示する必要があります。
まず、いくつかの変数を定義しました。 totalNumbers
は、コントロールに表示される合計ページ数を表します。 totalBlocks
は、表示される合計ページ数に加えて、左右のページインジケーター用の2つの追加ブロックを表します。
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="#" aria-label="Previous" onClick={this.handleMoveLeft}> <span aria-hidden="true">«</span> <span className="sr-only">Previous</span> </a> </li> ); if (page === RIGHT_PAGE) return ( <li key={index} className="page-item"> <a className="page-link" href="#" aria-label="Next" onClick={this.handleMoveRight}> <span aria-hidden="true">»</span> <span className="sr-only">Next</span> </a> </li> ); return ( <li key={index} className={`page-item${ currentPage === page ? ' active' : ''}`}> <a className="page-link" href="#" onClick={ this.handleClick(page) }>{ page }</a> </li> ); }) } </ul> </nav> </Fragment> ); } }
ここでは、前に作成したfetchPageNumbers()
メソッドを呼び出して、ページ番号array
を生成します。 次に、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); } }
状態を変更し、currentPage
を指定されたページに設定するgotoPage()
メソッドを定義します。 これにより、page
引数の最小値が1
になり、最大値が合計ページ数になります。 最後に、小道具として渡されたonPageChanged()
関数を呼び出し、データは新しいページネーション状態を示します。
コンポーネントがマウントされたら、componentDidMount()
ライフサイクルメソッドに示されているように、this.gotoPage(1)
を呼び出して最初のページに移動します。
handleMoveLeft()
およびhandleMoveRight()
で(this.pageNeighbours * 2)
を使用して、現在のページ番号に基づいてページ番号をそれぞれ左および右にスライドする方法に注目してください。
これは、左から右への動きの相互作用のデモです。
これで、Pagination
コンポーネントが完成しました。 ユーザーは、このコンポーネントのナビゲーションコントロールを操作して、さまざまなページのフラグを表示できます。
ステップ4—App
コンポーネントを構築する
CountryCard
およびPagination
コンポーネントができたので、これらをApp
コンポーネントで使用できます。
src
ディレクトリのApp.js
ファイルを変更します。
nano src/App.js
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.findAll()
を呼び出して、countries-api
パッケージを使用してすべての世界の国をフェッチします。 次に、アプリの状態を更新し、allCountries
を設定してすべての世界の国を含めます。 パッケージの詳細については、countries-apiドキュメントを参照してください。
最後に、onPageChanged()
メソッドを定義しました。このメソッドは、ページネーションコントロールから新しいページに移動するたびに呼び出されます。 このメソッドは、Pagination
コンポーネントのonPageChanged
プロップに渡されます。
この方法で注意を払う価値のある2つの行があります。 最初はこの行です:
const offset = (currentPage - 1) * pageLimit;
offset
値は、現在のページのレコードをフェッチするための開始インデックスを示します。 (currentPage - 1)
を使用すると、オフセットがゼロベースになります。 たとえば、ページごとに25
レコードを表示していて、現在ページ5
を表示しているとします。 その場合、offset
は((5 - 1) * 25 = 100)
になります。
たとえば、データベースからオンデマンドでレコードをフェッチしている場合、これはオフセットの使用方法を示すサンプルSQLクエリです。
SELECT * FROM `countries` LIMIT 100, 25
データベースや外部ソースからレコードをフェッチしていないため、現在のページに表示される必要なレコードのチャンクを抽出する方法が必要です。
2番目はこの行です:
const currentCountries = allCountries.slice(offset, offset + pageLimit);
ここでは、Array.prototype.slice()
メソッドを使用して、スライスの開始インデックスとしてoffset
を渡し、(offset + pageLimit)
を渡すことにより、allCountries
から必要なレコードのチャンクを抽出します。スライスを終了する前のインデックス。
注:このチュートリアルでは、外部ソースからレコードをフェッチしていません。 実際のアプリケーションでは、おそらくデータベースまたはAPIからレコードをフェッチすることになります。 レコードをフェッチするためのロジックは、App
コンポーネントのonPageChanged()
メソッドに入ることができます。
架空のAPIエンドポイント/api/countries?page={current_page}&limit={page_limit}
があるとします。 次のスニペットは、 axiosHTTPパッケージを使用してAPIからオンデマンドで国を取得する方法を示しています。
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 }); }); }
これで、render()
メソッドを追加して、App
コンポーネントを完成させることができます。
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()
メソッドを<Pagination>
コントロールのonPageChanged
プロップに渡したことに注意してください。 これは、Pagination
コンポーネントからページの変更をキャプチャするために非常に重要です。 また、ページごとに18
の国を表示しています。
この時点で、アプリは次のスクリーンショットのようになります。
これで、複数のCountryCard
コンポーネントを表示するApp
コンポーネントと、コンテンツを別々のページに分割するPagination
コンポーネントができました。 次に、アプリケーションのスタイリングについて説明します。
ステップ5—カスタムスタイルを追加する
以前に作成したコンポーネントにいくつかのカスタムクラスを追加していることに気付いたかもしれません。 src/App.scss
ファイルでこれらのクラスのスタイルルールを定義しましょう。
nano 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.css
ではなくApp.scss
を参照するようにApp.js
ファイルを変更します。
注:これについて詳しくは、 CreateReactAppドキュメントを参照してください。
nano src/App.js
src / App.js
import React, { Component } from 'react'; import Countries from 'countries-api'; import './App.scss'; import Pagination from './components/Pagination'; import CountryCard from './components/CountryCard';
スタイルを追加すると、アプリは次のスクリーンショットのようになります。
これで、追加のカスタムスタイルを備えた完全なアプリケーションができました。 カスタムスタイルを使用して、Bootstrapなどのライブラリによって提供されるデフォルトのスタイルを変更および拡張できます。
結論
このチュートリアルでは、Reactアプリケーションでカスタムページネーションウィジェットを作成しました。 このチュートリアルでは、APIを呼び出したり、データベースバックエンドとやり取りしたりしていませんが、アプリケーションでそのようなやり取りが必要になる場合があります。 このチュートリアルで使用されているアプローチに制限されることはありません。アプリケーションの要件に合わせて、アプローチを拡張できます。
このチュートリアルの完全なソースコードについては、GitHubのbuild-react-pagination-demoリポジトリを確認してください。 また、CodeSandboxでこのチュートリアルのライブデモを入手することもできます。
Reactの詳細については、 React.js シリーズのコーディング方法をご覧になるか、Reactトピックページで演習やプログラミングプロジェクトを確認してください。