序章

多くの場合、リモートサーバー、API、またはデータベースから大量のデータレコードをフェッチする必要があるWebアプリケーションの構築に関与します。 たとえば、支払いシステムを構築している場合、何千ものトランザクションをフェッチしている可能性があります。 ソーシャルメディアアプリの場合、多くのユーザーコメント、プロファイル、またはアクティビティを取得している可能性があります。 いずれの場合でも、アプリを操作するエンドユーザーを圧倒しない方法でデータを表示するためのソリューションがいくつかあります。

大規模なデータセットを処理する1つの方法は、paginationを使用することです。 データセットのサイズ(データセット内のレコードの総数)が事前にわかっている場合、ページネーションは効果的に機能します。 次に、エンドユーザーとページネーションコントロールの相互作用に基づいて、データセット全体から必要なデータのチャンクのみをロードします。 これは、Google検索で検索結果を表示するために使用される手法です。

このチュートリアルでは、大規模なデータセットをページ付けするためにReactを使用してカスタムページ付けコンポーネントを構築する方法を学習します。 世界の国々のページ分割されたビュー(既知のサイズのデータセット)を作成します。

これは、このチュートリアルで構築するもののデモです。

Demo App Screenshot — showing the countries of the world

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • ノードがマシンにインストールされています。 手順は、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-scriptsv3.4.1で検証されました。

ステップ1—プロジェクトの設定

create-react-appコマンドを使用して新しいReactアプリケーションを起動します。 アプリケーションには任意の名前を付けることができますが、このチュートリアルではreact-paginationという名前を付けます。

  1. npx create-react-app react-pagination

次に、アプリケーションに必要な依存関係をインストールします。 まず、ターミナルウィンドウを使用して、プロジェクトディレクトリに移動します。

  1. cd react-pagination

次のコマンドを実行して、必要な依存関係をインストールします。

  1. 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

これにより、bootstrapprop-typesreact-flagscountries-api、およびnode-sassがインストールされます。

デフォルトのスタイルが必要になるため、アプリケーションの依存関係としてbootstrapパッケージをインストールしました。 Bootstrappaginationコンポーネントのスタイルも使用します。

アプリケーションにブートストラップを含めるには、src/index.jsファイルを編集します。

  1. nano src/index.js

そして、他のimportステートメントの前に次の行を追加します。

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

これで、Bootstrapスタイリングがアプリケーション全体で利用できるようになります。

また、アプリケーションの依存関係としてreact-flagsをインストールしました。 アプリケーションからフラグアイコンにアクセスするには、アイコン画像をアプリケーションのpublicディレクトリにコピーする必要があります。

publicディレクトリにimgディレクトリを作成します。

  1. mkdir public/img

flagsの画像ファイルをimgにコピーします。

  1. cp -R node_modules/react-flags/vendor/flags public/img

これにより、すべてのreact-flagイメージのコピーがアプリケーションに提供されます。

いくつかの依存関係を含めたので、react-paginationプロジェクトディレクトリからnpmを指定して次のコマンドを実行し、アプリケーションを起動します。

  1. npm start

アプリケーションを開始したので、開発を開始できます。 ライブリロード機能を備えたブラウザタブが開いており、開発中にアプリケーションとの同期を維持していることに注意してください。

この時点で、アプリケーションビューは次のスクリーンショットのようになります。

Initial View – Welcome to React Screen

これで、コンポーネントの作成を開始する準備が整いました。

ステップ2—CountryCardコンポーネントを作成する

このステップでは、CountryCardコンポーネントを作成します。 CountryCardコンポーネントは、特定の国の名前、地域、および旗をレンダリングします。

まず、srcディレクトリにcomponentsディレクトリを作成しましょう。

  1. mkdir src/components

次に、src/componentsディレクトリに新しいCountryCard.jsファイルを作成します。

  1. 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ファイルを作成します。

  1. 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プロップのさまざまな値の効果を示しています。

Page Neighbours Illustration

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_PAGERIGHT_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つの追加ブロックを表します。

totalPagestotalBlocks以下の場合、1からtotalPagesまでの数値の範囲を返します。 それ以外の場合は、ページ番号の配列を返します。ページが左右にこぼれるポイントには、それぞれLEFT_PAGERIGHT_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">&laquo;</span>
                    <span className="sr-only">Previous</span>
                  </a>
                </li>
              );

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

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

            }) }

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

ここでは、前に作成した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)を使用して、現在のページ番号に基づいてページ番号をそれぞれ左および右にスライドする方法に注目してください。

これは、左から右への動きの相互作用のデモです。

Left-Right Movement of the interaction

これで、Paginationコンポーネントが完成しました。 ユーザーは、このコンポーネントのナビゲーションコントロールを操作して、さまざまなページのフラグを表示できます。

ステップ4—Appコンポーネントを構築する

CountryCardおよびPaginationコンポーネントができたので、これらをAppコンポーネントで使用できます。

srcディレクトリのApp.jsファイルを変更します。

  1. 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クラスで、componentDidMountonPageChangedの後に、次の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の国を表示しています。

この時点で、アプリは次のスクリーンショットのようになります。

App Screenshot with 248 countries listed and page numbers to the top to go through each page

これで、複数のCountryCardコンポーネントを表示するAppコンポーネントと、コンテンツを別々のページに分割するPaginationコンポーネントができました。 次に、アプリケーションのスタイリングについて説明します。

ステップ5—カスタムスタイルを追加する

以前に作成したコンポーネントにいくつかのカスタムクラスを追加していることに気付いたかもしれません。 src/App.scssファイルでこれらのクラスのスタイルルールを定義しましょう。

  1. 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ドキュメントを参照してください。

  1. 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';

スタイルを追加すると、アプリは次のスクリーンショットのようになります。

App Screenshot page 1 of 14, with Styles

これで、追加のカスタムスタイルを備えた完全なアプリケーションができました。 カスタムスタイルを使用して、Bootstrapなどのライブラリによって提供されるデフォルトのスタイルを変更および拡張できます。

結論

このチュートリアルでは、Reactアプリケーションでカスタムページネーションウィジェットを作成しました。 このチュートリアルでは、APIを呼び出したり、データベースバックエンドとやり取りしたりしていませんが、アプリケーションでそのようなやり取りが必要になる場合があります。 このチュートリアルで使用されているアプローチに制限されることはありません。アプリケーションの要件に合わせて、アプローチを拡張できます。

このチュートリアルの完全なソースコードについては、GitHubのbuild-react-pagination-demoリポジトリを確認してください。 また、CodeSandboxでこのチュートリアルのライブデモを入手することもできます。

Reactの詳細については、 React.js シリーズのコーディング方法をご覧になるか、Reactトピックページで演習やプログラミングプロジェクトを確認してください。