Thứ năm, 17/09/2020 | 00:00 GMT+7

Cách tạo phân trang tùy chỉnh với React

Ta thường tham gia vào việc xây dựng các ứng dụng web nơi ta cần tìm nạp các tập hợp lớn các bản ghi dữ liệu từ server từ xa, API hoặc database . Ví dụ: nếu bạn đang xây dựng một hệ thống thanh toán, nó có thể đang tìm nạp hàng nghìn giao dịch. Nếu đó là một ứng dụng truyền thông xã hội, nó có thể tìm nạp nhiều comment , profile hoặc hoạt động của user . Dù trường hợp nào xảy ra, có một số giải pháp để trình bày dữ liệu theo cách không lấn át user cuối tương tác với ứng dụng.

Một phương pháp để xử lý các tập dữ liệu lớn là sử dụng phân trang . Phân trang hoạt động hiệu quả khi bạn đã biết trước kích thước của tập dữ liệu (tổng số bản ghi trong tập dữ liệu). Thứ hai, bạn chỉ tải phần dữ liệu cần thiết từ tổng số tập dữ liệu dựa trên tương tác của user cuối với kiểm soát phân trang. Đây là kỹ thuật được sử dụng để hiển thị kết quả tìm kiếm trong Google Tìm kiếm.

Trong hướng dẫn này, bạn sẽ học cách xây dựng một thành phần phân trang tùy chỉnh với React để phân trang các tập dữ liệu lớn. Bạn sẽ xây dựng một chế độ xem phân trang về các quốc gia trên thế giới - một tập dữ liệu với kích thước đã biết.

Đây là bản demo về những gì bạn sẽ xây dựng trong hướng dẫn này:

Demo Ảnh chụp màn hình ứng dụng - hiển thị các quốc gia trên thế giới

Yêu cầu

Để hoàn thành hướng dẫn này, bạn cần :

Hướng dẫn này đã được xác minh với Node v14.2.0, npm v6.14.4, react v16.13.1, và react-scripts v3.4.1.

Bước 1 - Cài đặt dự án

Khởi động một ứng dụng React mới bằng lệnh create-react-app . Bạn có thể đặt tên ứng dụng bạn muốn , nhưng hướng dẫn này sẽ đặt tên là react-pagination :

  • npx create-react-app react-pagination

Tiếp theo, bạn sẽ cài đặt các phụ thuộc cần thiết cho ứng dụng của bạn . Đầu tiên, sử dụng cửa sổ terminal để chuyển đến folder dự án:

  • cd react-pagination

Chạy lệnh sau để cài đặt các phụ thuộc :

  • 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

Thao tác này sẽ cài đặt bootstrap , prop-types , react-flags , countries-apinode-sass .

Bạn đã cài đặt gói bootstrap làm phụ thuộc cho ứng dụng của bạn vì bạn cần một số kiểu mặc định. Bạn cũng sẽ sử dụng các kiểu từ thành phần pagination Bootstrap.

Để đưa Bootstrap vào ứng dụng, hãy chỉnh sửa file src/index.js :

  • nano src/index.js

Và thêm dòng sau trước các câu lệnh import khác:

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

Bây giờ, kiểu Bootstrap sẽ có sẵn trong ứng dụng của bạn.

Bạn cũng đã cài đặt react-flags làm phụ thuộc cho ứng dụng của bạn . Để có quyền truy cập vào các biểu tượng cờ từ ứng dụng của bạn, bạn cần sao chép các hình ảnh biểu tượng vào folder public của ứng dụng.

Tạo một img folder trong bạn public folder :

  • mkdir public/img

Sao chép các file hình ảnh trong flags vào img :

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

Điều này cung cấp một bản sao của tất cả các hình ảnh react-flag cho ứng dụng của bạn.

Đến đây bạn đã bao gồm một số phụ thuộc, hãy khởi động ứng dụng bằng cách chạy lệnh sau với npm từ folder dự án react-pagination :

  • npm start

Đến đây bạn đã khởi động ứng dụng, quá trình phát triển có thể bắt đầu. Lưu ý một tab trình duyệt đã được mở cho bạn với chức năng reload trực tiếp để giữ đồng bộ với ứng dụng khi bạn phát triển.

Đến đây, chế độ xem ứng dụng sẽ giống như ảnh chụp màn hình sau:

Chế độ xem ban đầu - Chào mừng bạn đến với Màn hình phản ứng

Đến đây bạn đã sẵn sàng để bắt đầu tạo các thành phần.

Bước 2 - Tạo thành phần CountryCard

Trong bước này, bạn sẽ tạo thành phần CountryCard . Thành phần CountryCard hiển thị tên, khu vực và cờ của một quốc gia nhất định.

Đầu tiên, hãy tạo một folder components trong folder src :

  • mkdir src/components

Sau đó, tạo một file CountryCard.js mới trong folder src/components :

  • nano src/components/CountryCard.js

Và thêm đoạn mã sau vào đó:

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; 

Thành phần CountryCard yêu cầu một bộ phận hỗ trợ country có chứa dữ liệu về quốc gia được hiển thị. Như đã thấy trong propTypes cho thành phần CountryCard , đối tượng country prop phải chứa dữ liệu sau:

  • cca2 - mã quốc gia gồm 2 chữ số
  • region - region quốc gia (ví dụ: "Châu Phi")
  • name.common - tên thông thường của quốc gia (ví dụ: “Nigeria”)

Đây là một đối tượng quốc gia mẫu:

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

Ngoài ra, hãy lưu ý cách bạn hiển thị cờ quốc gia bằng cách sử dụng gói react-flags . Bạn có thể kiểm tra tài liệu về react-flags để tìm hiểu thêm về các đạo cụ cần thiết và cách sử dụng gói.

Đến đây bạn đã hoàn thành một thành phần CountryCard riêng lẻ. Cuối cùng, bạn sẽ sử dụng CountryCard nhiều lần để hiển thị các cờ khác nhau và thông tin quốc gia trong ứng dụng của bạn.

Bước 3 - Tạo Pagination Component

Trong bước này, bạn sẽ tạo thành phần Pagination . Thành phần Pagination chứa logic để xây dựng, kết xuất và chuyển đổi các trang trên điều khiển phân trang.

Tạo file Pagination.js mới trong folder src/components :

  • nano src/components/Pagination.js

Và thêm đoạn mã sau vào đó:

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; 

Các Pagination thành phần có thể mất bốn đạo cụ đặc biệt theo quy định tại các propTypes đối tượng.

  • onPageChanged là một hàm được gọi với dữ liệu của trạng thái phân trang hiện tại chỉ khi trang hiện tại thay đổi.
  • totalRecords cho biết tổng số bản ghi được phân trang. Nó là bắt buộc.
  • pageLimit cho biết số lượng bản ghi được hiển thị trên mỗi trang. Nếu không được chỉ định, nó mặc định là 30 như được định nghĩa trong hàm constructor() .
  • pageNeighbours cho biết số lượng trang bổ sung sẽ hiển thị ở mỗi bên của trang hiện tại. Giá trị nhỏ nhất là 0 và giá trị lớn nhất là 2 . Nếu không được chỉ định, nó sẽ mặc định là 0 như được định nghĩa trong hàm constructor() .

Hình ảnh sau đây minh họa tác động của các giá trị khác nhau của pageNeighbours prop:

Trang minh họa hàng xóm

Trong hàm constructor() , bạn tính tổng số trang như sau:

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

Lưu ý bạn sử dụng Math.ceil() ở đây đảm bảo rằng bạn nhận được một giá trị nguyên cho tổng số trang. Điều này cũng đảm bảo các bản ghi thừa được ghi lại trong trang cuối cùng, đặc biệt là trong trường hợp số lượng bản ghi thừa ít hơn số lượng bản ghi được hiển thị trên mỗi trang.

Cuối cùng, bạn khởi tạo trạng thái với thuộc tính currentPage được đặt thành 1 . Bạn cần thuộc tính trạng thái này để theo dõi trang hiện đang hoạt động trong nội bộ.

Tiếp theo, bạn sẽ tạo phương thức tạo số trang.

Sau khi import s nhưng trước khi Pagination lớp, thêm các hằng số và sau range chức năng:

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

Trong lớp Pagination , sau hàm constructor , hãy thêm phương thức fetchPageNumbers sau:

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

Ở đây, trước tiên bạn xác định hai hằng số: LEFT_PAGERIGHT_PAGE . Các hằng số này sẽ được sử dụng để chỉ ra các điểm mà bạn có các điều khiển trang để di chuyển sang trái và phải tương ứng.

Bạn cũng đã xác định một hàm trợ giúp range() có thể giúp bạn tạo các dải số.

Lưu ý: Nếu bạn sử dụng thư viện tiện ích như Lodash trong dự án của bạn , thì bạn có thể sử dụng hàm _.range() do Lodash cung cấp để thay thế. Đoạn mã sau đây cho thấy sự khác biệt giữa hàm range() bạn vừa xác định và hàm từ Lodash:

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

Tiếp theo, bạn đã xác định phương thức fetchPageNumbers() trong lớp Pagination . Phương pháp này xử lý logic cốt lõi để tạo số trang được hiển thị trên điều khiển phân trang. Bạn muốn trang đầu tiên và trang cuối cùng luôn hiển thị.

Đầu tiên, bạn đã xác định một vài biến. totalNumbers đại diện cho tổng số trang sẽ được hiển thị trên điều khiển. totalBlocks đại diện cho tổng số trang được hiển thị cộng với hai khối bổ sung cho các chỉ báo trang bên trái và bên phải.

Nếu totalPages không lớn hơn totalBlocks , bạn trả về một dải số từ 1 đến totalPages . Nếu không, bạn trả về mảng số trang, với LEFT_PAGERIGHT_PAGE tại các điểm mà bạn có các trang tràn sang trái và phải tương ứng.

Tuy nhiên, lưu ý kiểm soát phân trang web đảm bảo trang đầu tiên và trang cuối cùng luôn hiển thị. Các điều khiển trang bên trái và bên phải xuất hiện bên trong.

Bây giờ, bạn sẽ thêm phương thức render() để cho phép bạn hiển thị điều khiển phân trang.

Trong lớp Pagination , sau phương thức constructorfetchPageNumbers , hãy thêm phương thức render sau:

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

Tại đây, bạn tạo array số trang bằng cách gọi phương thức fetchPageNumbers() mà bạn đã tạo trước đó. Sau đó, bạn kết xuất từng số trang bằng Array.prototype.map() . Lưu ý bạn đăng ký trình xử lý sự kiện nhấp chuột trên mỗi số trang được hiển thị để xử lý nhấp chuột.

Ngoài ra, thông báo rằng việc kiểm soát pagination sẽ không được trả lại nếu totalRecords prop đã không được thông qua một cách chính xác đến Pagination thành phần hoặc trong trường hợp chỉ có 1 trang.

Cuối cùng, bạn sẽ xác định các phương thức xử lý sự kiện.

Trong lớp Pagination , sau phương thức constructorfetchPageNumbers và phương thức render , hãy thêm phần sau:

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

Bạn xác định phương thức gotoPage() sửa đổi trạng thái và đặt currentPage thành trang được chỉ định. Nó đảm bảo đối số page có giá trị nhỏ nhất là 1 và giá trị lớn nhất của tổng số trang. Cuối cùng nó gọi hàm onPageChanged() đã được chuyển vào như một chỗ dựa, với dữ liệu chỉ ra trạng thái phân trang mới.

Khi thành phần mount , bạn đi đến trang đầu tiên bằng cách gọi this.gotoPage(1) như trong phương thức vòng đời componentDidMount() .

Lưu ý cách bạn sử dụng (this.pageNeighbours * 2) trong handleMoveLeft()handleMoveRight() để trượt số trang sang trái và phải tương ứng dựa trên số trang hiện tại.

Đây là bản demo về sự tương tác của chuyển động từ trái sang phải.

Chuyển động trái phải của tương tác

Đến đây bạn đã hoàn thành thành phần Pagination . User sẽ có thể tương tác với các công cụ chuyển trong thành phần này để hiển thị các trang cờ khác nhau.

Bước 4 - Xây dựng thành phần App

Đến đây bạn đã có thành phần CountryCardPagination , bạn có thể sử dụng chúng trong thành phần App của bạn .

Sửa đổi file App.js trong folder src :

  • nano src/App.js

Thay thế nội dung của App.js bằng các dòng mã sau:

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; 

Tại đây, bạn khởi tạo trạng thái của thành phần App với các thuộc tính sau:

  • allCountries - Đây là một mảng gồm tất cả các quốc gia trong ứng dụng của bạn. Được khởi tạo thành một mảng trống ( [] ).
  • currentCountries - Đây là một mảng gồm tất cả các quốc gia sẽ được hiển thị trên trang hiện đang hoạt động. Được khởi tạo thành một mảng trống ( [] ).
  • currentPage - Số trang của trang hiện đang hoạt động. Khởi tạo thành null .
  • totalPages - Tổng số trang cho tất cả các bản ghi quốc gia. Khởi tạo thành null .

Tiếp theo, trong phương thức vòng đời componentDidMount() , bạn tìm nạp tất cả các quốc gia trên thế giới bằng cách sử dụng gói countries-api bằng cách gọi Countries.findAll() . Sau đó, bạn cập nhật trạng thái ứng dụng, đặt allCountries để chứa tất cả các quốc gia trên thế giới. Bạn có thể xem tài liệu countries-api để tìm hiểu thêm về gói.

Cuối cùng, bạn đã xác định phương thức onPageChanged() , phương thức này sẽ được gọi mỗi khi bạn chuyển đến một trang mới từ điều khiển phân trang. Phương pháp này sẽ được chuyển đến các onPageChanged prop của Pagination thành phần.

Có hai dòng đáng chú ý trong phương pháp này. Đầu tiên là dòng này:

const offset = (currentPage - 1) * pageLimit; 

Giá trị offset cho biết index bắt đầu để tìm nạp các bản ghi cho trang hiện tại. Sử dụng (currentPage - 1) đảm bảo độ lệch là không. Ví dụ: giả sử bạn đang hiển thị 25 bản ghi trên mỗi trang và bạn hiện đang xem trang 5 . Khi đó phần offset sẽ là ((5 - 1) * 25 = 100) .

Ví dụ: nếu bạn đang tìm nạp các bản ghi theo yêu cầu từ database , đây là một truy vấn SQL mẫu để cho bạn biết cách sử dụng bù đắp:

SELECT * FROM `countries` LIMIT 100, 25 

Vì bạn không tìm nạp các bản ghi từ database hoặc bất kỳ nguồn bên ngoài nào, nên bạn cần một cách để extract group bản ghi cần thiết để hiển thị cho trang hiện tại.

Thứ hai là dòng này:

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

Ở đây bạn sử dụng phương thức Array.prototype.slice() để extract đoạn bản ghi bắt buộc từ allCountries bằng cách chuyển offset làm index bắt đầu cho lát và (offset + pageLimit) làm index trước đó để kết thúc lát.

Lưu ý: Trong hướng dẫn này, bạn không tìm nạp bản ghi từ bất kỳ nguồn bên ngoài nào. Trong một ứng dụng thực, có thể bạn sẽ tìm nạp các bản ghi từ database hoặc API. Logic để tìm nạp các bản ghi có thể đi vào phương thức onPageChanged() của thành phần App .

Giả sử bạn có một điểm cuối API hư cấu /api/countries?page={current_page}&limit={page_limit} . Đoạn mã sau đây cho thấy cách bạn có thể tìm nạp các quốc gia theo yêu cầu từ API bằng cách sử dụng gói HTTP axios :

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

Bây giờ, bạn có thể hoàn tất thành phần App bằng cách thêm phương thức render() .

Trong lớp App , nhưng sau componentDidMountonPageChanged , hãy thêm phương thức render sau:

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

Trong phương thức render() , bạn kết xuất tổng số quốc gia, trang hiện tại, tổng số trang, điều khiển <Pagination> và sau đó là <CountryCard> cho mỗi quốc gia trong trang hiện tại.

Lưu ý bạn đã chuyển phương thức onPageChanged() mà bạn đã xác định trước đó vào phần hỗ trợ onPageChanged của điều khiển <Pagination> . Đây là điều rất quan trọng để chụp thay đổi trang từ Pagination thành phần. Bạn cũng đang hiển thị 18 quốc gia trên mỗi trang.

Đến đây, ứng dụng sẽ giống như ảnh chụp màn hình sau:

Ảnh chụp màn hình ứng dụng với 248 quốc gia được liệt kê và số trang ở trên cùng để xem qua từng trang

Đến đây bạn có một App thành phần hiển thị nhiều CountryCard thành phần và một Pagination thành phần phá vỡ lên nội dung vào các trang riêng biệt. Tiếp theo, bạn sẽ khám phá cách tạo kiểu cho ứng dụng của bạn .

Bước 5 - Thêm kiểu tùy chỉnh

Bạn có thể nhận thấy rằng bạn đã thêm một số lớp tùy chỉnh vào các thành phần bạn đã tạo trước đó. Hãy xác định một số luật kiểu cho các lớp đó trong file src/App.scss .

  • nano src/App.scss

Tệp App.scss sẽ giống như đoạn mã sau:

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

Sửa đổi file App.js của bạn thành tham chiếu App.scss thay vì App.css .

Lưu ý: Để biết thêm thông tin về điều này, hãy xem tài liệu Tạo ứng dụng React .

  • 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'; 

Sau khi thêm các kiểu, ứng dụng bây giờ sẽ giống như ảnh chụp màn hình sau:

Ảnh chụp màn hình ứng dụng trang 1 trên 14, với Kiểu

Đến đây bạn có một ứng dụng hoàn chỉnh với kiểu tùy chỉnh bổ sung. Bạn có thể sử dụng các kiểu tùy chỉnh để sửa đổi và nâng cao bất kỳ kiểu mặc định nào được cung cấp bởi các thư viện như Bootstrap.

Kết luận

Trong hướng dẫn này, bạn đã tạo một widget phân trang tùy chỉnh trong ứng dụng React của bạn . Mặc dù bạn không thực hiện lệnh gọi đến bất kỳ API nào hoặc tương tác với bất kỳ phần mềm backend database nào trong hướng dẫn này, ứng dụng của bạn có thể yêu cầu các tương tác như vậy. Bạn không bị giới hạn bởi bất kỳ cách nào đối với cách tiếp cận được sử dụng trong hướng dẫn này - bạn có thể mở rộng nó tùy ý để phù hợp với các yêu cầu của ứng dụng của bạn.

Để có mã nguồn hoàn chỉnh của hướng dẫn này, hãy xem repository build-react-pagination-demo trên GitHub. Bạn cũng có thể nhận bản demo trực tiếp của hướng dẫn này trên Code Sandbox .

Nếu bạn muốn tìm hiểu thêm về React, hãy xem loạt bài Cách viết mã trong React.js của ta hoặc xem trang chủ đề React của ta để biết các bài tập và dự án lập trình.


Tags:

Các tin liên quan