如何在 React 中实现分页

我是 ReactJS 的新手,正在其中创建一个简单的 TODO 应用程序。实际上,它是一个非常基本的应用程序,没有数据库连接,任务存储在一个数组中。我添加了编辑和删除功能,现在我要添加分页。

我该如何实施呢? 任何帮助都将不胜感激。谢谢你... ! !

208819 次浏览

给你一个分页组件,这对于新手来说可能有点难以理解到 react:

Https://www.npmjs.com/package/pagination

我最近用纯 React JS 实现了分页

当然,您必须调整逻辑和显示页码的方式,以便满足您的需求。

完整代码:

class TodoApp extends React.Component {
constructor() {
super();
this.state = {
todos: ['a','b','c','d','e','f','g','h','i','j','k'],
currentPage: 1,
todosPerPage: 3
};
this.handleClick = this.handleClick.bind(this);
}


handleClick(event) {
this.setState({
currentPage: Number(event.target.id)
});
}


render() {
const { todos, currentPage, todosPerPage } = this.state;


// Logic for displaying todos
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
const currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);


const renderTodos = currentTodos.map((todo, index) => {
return <li key={index}>{todo}</li>;
});


// Logic for displaying page numbers
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(todos.length / todosPerPage); i++) {
pageNumbers.push(i);
}


const renderPageNumbers = pageNumbers.map(number => {
return (
<li
key={number}
id={number}
onClick={this.handleClick}
>
{number}
</li>
);
});


return (
<div>
<ul>
{renderTodos}
</ul>
<ul id="page-numbers">
{renderPageNumbers}
</ul>
</div>
);
}
}




ReactDOM.render(
<TodoApp />,
document.getElementById('app')
);

我最近创建了这个 Pagination 组件,它实现了像 Google 搜索结果这样的分页逻辑:

import React, { PropTypes } from 'react';
 
const propTypes = {
    items: PropTypes.array.isRequired,
    onChangePage: PropTypes.func.isRequired,
    initialPage: PropTypes.number   
}
 
const defaultProps = {
    initialPage: 1
}
 
class Pagination extends React.Component {
    constructor(props) {
        super(props);
        this.state = { pager: {} };
    }
 
    componentWillMount() {
        this.setPage(this.props.initialPage);
    }
 
    setPage(page) {
        var items = this.props.items;
        var pager = this.state.pager;
 
        if (page < 1 || page > pager.totalPages) {
            return;
        }
 
        // get new pager object for specified page
        pager = this.getPager(items.length, page);
 
        // get new page of items from items array
        var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
 
        // update state
        this.setState({ pager: pager });
 
        // call change page function in parent component
        this.props.onChangePage(pageOfItems);
    }
 
    getPager(totalItems, currentPage, pageSize) {
        // default to first page
        currentPage = currentPage || 1;
 
        // default page size is 10
        pageSize = pageSize || 10;
 
        // calculate total pages
        var totalPages = Math.ceil(totalItems / pageSize);
 
        var startPage, endPage;
        if (totalPages <= 10) {
            // less than 10 total pages so show all
            startPage = 1;
            endPage = totalPages;
        } else {
            // more than 10 total pages so calculate start and end pages
            if (currentPage <= 6) {
                startPage = 1;
                endPage = 10;
            } else if (currentPage + 4 >= totalPages) {
                startPage = totalPages - 9;
                endPage = totalPages;
            } else {
                startPage = currentPage - 5;
                endPage = currentPage + 4;
            }
        }
 
        // calculate start and end item indexes
        var startIndex = (currentPage - 1) * pageSize;
        var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
 
        // create an array of pages to ng-repeat in the pager control
        var pages = _.range(startPage, endPage + 1);
 
        // return object with all pager properties required by the view
        return {
            totalItems: totalItems,
            currentPage: currentPage,
            pageSize: pageSize,
            totalPages: totalPages,
            startPage: startPage,
            endPage: endPage,
            startIndex: startIndex,
            endIndex: endIndex,
            pages: pages
        };
    }
 
    render() {
        var pager = this.state.pager;
 
        return (
            <ul className="pagination">
                <li className={pager.currentPage === 1 ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(1)}>First</a>
                </li>
                <li className={pager.currentPage === 1 ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(pager.currentPage - 1)}>Previous</a>
                </li>
                {pager.pages.map((page, index) =>
                    <li key={index} className={pager.currentPage === page ? 'active' : ''}>
                        <a onClick={() => this.setPage(page)}>{page}</a>
                    </li>
                )}
                <li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(pager.currentPage + 1)}>Next</a>
                </li>
                <li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(pager.totalPages)}>Last</a>
                </li>
            </ul>
        );
    }
}
 
Pagination.propTypes = propTypes;
Pagination.defaultProps
export default Pagination;

下面是一个示例 App 组件,它使用 Pagination 组件对包含150个示例项的列表进行分页:

import React from 'react';
import Pagination from './Pagination';
 
class App extends React.Component {
    constructor() {
        super();
 
        // an example array of items to be paged
        var exampleItems = _.range(1, 151).map(i => { return { id: i, name: 'Item ' + i }; });
 
        this.state = {
            exampleItems: exampleItems,
            pageOfItems: []
        };
 
        // bind function in constructor instead of render (https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)
        this.onChangePage = this.onChangePage.bind(this);
    }
 
    onChangePage(pageOfItems) {
        // update state with new page of items
        this.setState({ pageOfItems: pageOfItems });
    }
 
    render() {
        return (
            <div>
                <div className="container">
                    <div className="text-center">
                        <h1>React - Pagination Example with logic like Google</h1>
                        {this.state.pageOfItems.map(item =>
                            <div key={item.id}>{item.name}</div>
                        )}
                        <Pagination items={this.state.exampleItems} onChangePage={this.onChangePage} />
                    </div>
                </div>
                <hr />
                <div className="credits text-center">
                    <p>
                        <a href="http://jasonwatmore.com" target="_top">JasonWatmore.com</a>
                    </p>
                </div>
            </div>
        );
    }
}
 
export default App;

更多的细节和一个现场演示,你可以查看 这篇文章

   Sample pagination react js working code
import React, { Component } from 'react';
import {
Pagination,
PaginationItem,
PaginationLink
} from "reactstrap";




let prev  = 0;
let next  = 0;
let last  = 0;
let first = 0;
export default class SamplePagination extends Component {
constructor() {
super();
this.state = {
todos: ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','T','v','u','w','x','y','z'],
currentPage: 1,
todosPerPage: 3,


};
this.handleClick = this.handleClick.bind(this);
this.handleLastClick = this.handleLastClick.bind(this);
this.handleFirstClick = this.handleFirstClick.bind(this);
}


handleClick(event) {
event.preventDefault();
this.setState({
currentPage: Number(event.target.id)
});
}


handleLastClick(event) {
event.preventDefault();
this.setState({
currentPage:last
});
}
handleFirstClick(event) {
event.preventDefault();
this.setState({
currentPage:1
});
}
render() {
let { todos, currentPage, todosPerPage } = this.state;


// Logic for displaying current todos
let indexOfLastTodo = currentPage * todosPerPage;
let indexOfFirstTodo = indexOfLastTodo - todosPerPage;
let currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);
prev  = currentPage > 0 ? (currentPage -1) :0;
last = Math.ceil(todos.length/todosPerPage);
next  = (last === currentPage) ?currentPage: currentPage +1;


// Logic for displaying page numbers
let pageNumbers = [];
for (let i = 1; i <=last; i++) {
pageNumbers.push(i);
}


return (
<div>
<ul>
{
currentTodos.map((todo,index) =>{
return <li key={index}>{todo}</li>;
})
}
</ul><ul id="page-numbers">
<nav>
<Pagination>
<PaginationItem>
{ prev === 0 ? <PaginationLink disabled>First</PaginationLink> :
<PaginationLink onClick={this.handleFirstClick} id={prev} href={prev}>First</PaginationLink>
}
</PaginationItem>
<PaginationItem>
{ prev === 0 ? <PaginationLink disabled>Prev</PaginationLink> :
<PaginationLink onClick={this.handleClick} id={prev} href={prev}>Prev</PaginationLink>
}
</PaginationItem>
{
pageNumbers.map((number,i) =>
<Pagination key= {i}>
<PaginationItem active = {pageNumbers[currentPage-1] === (number) ? true : false} >
<PaginationLink onClick={this.handleClick} href={number} key={number} id={number}>
{number}
</PaginationLink>
</PaginationItem>
</Pagination>
)}


<PaginationItem>
{
currentPage === last ? <PaginationLink disabled>Next</PaginationLink> :
<PaginationLink onClick={this.handleClick} id={pageNumbers[currentPage]} href={pageNumbers[currentPage]}>Next</PaginationLink>
}
</PaginationItem>


<PaginationItem>
{
currentPage === last ? <PaginationLink disabled>Last</PaginationLink> :
<PaginationLink onClick={this.handleLastClick} id={pageNumbers[currentPage]} href={pageNumbers[currentPage]}>Last</PaginationLink>
}
</PaginationItem>
</Pagination>
</nav>
</ul>
</div>
);
}
}


ReactDOM.render(
<SamplePagination />,
document.getElementById('root')
);

我最近创建了一个库,可以帮助处理如下分页情况:

  • 在 Redux 中存储规范化数据
  • 基于搜索过滤器的网页缓存
  • 简化的反应-虚拟化列表使用
  • 背景中的清新结果
  • 存储最后访问的页面和使用过的过滤器

页面实现了上述所有特性。

你可以在 Github上找到源代码

我已经尝试重新创建由 Piotr-Berebecki给出的简单分页示例,这是伟大的。但是当有很多页面时,分页就会在屏幕上溢出。因此,我使用了前后按钮以及前后按钮来在页面之间来回流动。在设计部分我使用了自举3。

可以使用页绑定值自定义在分页中显示的任何页。确保 upperPageBound 和 pageBound 使用相同的值。

    class TodoApp extends React.Component {
constructor() {
super();
this.state = {
todos: ['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'],
currentPage: 1,
todosPerPage: 3,
upperPageBound: 3,
lowerPageBound: 0,
isPrevBtnActive: 'disabled',
isNextBtnActive: '',
pageBound: 3
};
this.handleClick = this.handleClick.bind(this);
this.btnDecrementClick = this.btnDecrementClick.bind(this);
this.btnIncrementClick = this.btnIncrementClick.bind(this);
this.btnNextClick = this.btnNextClick.bind(this);
this.btnPrevClick = this.btnPrevClick.bind(this);
// this.componentDidMount = this.componentDidMount.bind(this);
this.setPrevAndNextBtnClass = this.setPrevAndNextBtnClass.bind(this);
}
componentDidUpdate() {
$("ul li.active").removeClass('active');
$('ul li#'+this.state.currentPage).addClass('active');
}
handleClick(event) {
let listid = Number(event.target.id);
this.setState({
currentPage: listid
});
$("ul li.active").removeClass('active');
$('ul li#'+listid).addClass('active');
this.setPrevAndNextBtnClass(listid);
}
setPrevAndNextBtnClass(listid) {
let totalPage = Math.ceil(this.state.todos.length / this.state.todosPerPage);
this.setState({isNextBtnActive: 'disabled'});
this.setState({isPrevBtnActive: 'disabled'});
if(totalPage === listid && totalPage > 1){
this.setState({isPrevBtnActive: ''});
}
else if(listid === 1 && totalPage > 1){
this.setState({isNextBtnActive: ''});
}
else if(totalPage > 1){
this.setState({isNextBtnActive: ''});
this.setState({isPrevBtnActive: ''});
}
}
btnIncrementClick() {
this.setState({upperPageBound: this.state.upperPageBound + this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound + this.state.pageBound});
let listid = this.state.upperPageBound + 1;
this.setState({ currentPage: listid});
this.setPrevAndNextBtnClass(listid);
}
btnDecrementClick() {
this.setState({upperPageBound: this.state.upperPageBound - this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound - this.state.pageBound});
let listid = this.state.upperPageBound - this.state.pageBound;
this.setState({ currentPage: listid});
this.setPrevAndNextBtnClass(listid);
}
btnPrevClick() {
if((this.state.currentPage -1)%this.state.pageBound === 0 ){
this.setState({upperPageBound: this.state.upperPageBound - this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound - this.state.pageBound});
}
let listid = this.state.currentPage - 1;
this.setState({ currentPage : listid});
this.setPrevAndNextBtnClass(listid);
}
btnNextClick() {
if((this.state.currentPage +1) > this.state.upperPageBound ){
this.setState({upperPageBound: this.state.upperPageBound + this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound + this.state.pageBound});
}
let listid = this.state.currentPage + 1;
this.setState({ currentPage : listid});
this.setPrevAndNextBtnClass(listid);
}
render() {
const { todos, currentPage, todosPerPage,upperPageBound,lowerPageBound,isPrevBtnActive,isNextBtnActive } = this.state;
// Logic for displaying current todos
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
const currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);


const renderTodos = currentTodos.map((todo, index) => {
return <li key={index}>{todo}</li>;
});


// Logic for displaying page numbers
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(todos.length / todosPerPage); i++) {
pageNumbers.push(i);
}


const renderPageNumbers = pageNumbers.map(number => {
if(number === 1 && currentPage === 1){
return(
<li key={number} className='active' id={number}><a href='#' id={number} onClick={this.handleClick}>{number}</a></li>
)
}
else if((number < upperPageBound + 1) && number > lowerPageBound){
return(
<li key={number} id={number}><a href='#' id={number} onClick={this.handleClick}>{number}</a></li>
)
}
});
let pageIncrementBtn = null;
if(pageNumbers.length > upperPageBound){
pageIncrementBtn = <li className=''><a href='#' onClick={this.btnIncrementClick}> &hellip; </a></li>
}
let pageDecrementBtn = null;
if(lowerPageBound >= 1){
pageDecrementBtn = <li className=''><a href='#' onClick={this.btnDecrementClick}> &hellip; </a></li>
}
let renderPrevBtn = null;
if(isPrevBtnActive === 'disabled') {
renderPrevBtn = <li className={isPrevBtnActive}><span id="btnPrev"> Prev </span></li>
}
else{
renderPrevBtn = <li className={isPrevBtnActive}><a href='#' id="btnPrev" onClick={this.btnPrevClick}> Prev </a></li>
}
let renderNextBtn = null;
if(isNextBtnActive === 'disabled') {
renderNextBtn = <li className={isNextBtnActive}><span id="btnNext"> Next </span></li>
}
else{
renderNextBtn = <li className={isNextBtnActive}><a href='#' id="btnNext" onClick={this.btnNextClick}> Next </a></li>
}
return (
<div>
<ul>
{renderTodos}
</ul>
<ul id="page-numbers" className="pagination">
{renderPrevBtn}
{pageDecrementBtn}
{renderPageNumbers}
{pageIncrementBtn}
{renderNextBtn}
</ul>
</div>
);
}
}




ReactDOM.render(
<TodoApp />,
document.getElementById('app')
);

工作演示链接: https://codepen.io/mhmanandhar/pen/oEWBqx

图片来源: 简单反应式分页法

这里有一种方法来创建您的自定义分页组件从反应引导库和这个组件,您可以使用整个项目 enter image description here

您的分页组件(Pagination.jsx 或 js)

import React, { Component } from "react";
import { Pagination } from "react-bootstrap";
import PropTypes from "prop-types";


export default class PaginationHandler extends Component {


constructor(props) {
super(props);
this.state = {
paging: {
offset: 0,
limit: 10
},
active: 0
};
}


pagingHandler = () => {
let offset = parseInt(event.target.id);
this.setState({
active: offset
});
this.props.pageHandler(event.target.id - 1);   };


nextHandler = () => {
let active = this.state.active;
this.setState({
active: active + 1
});
this.props.pageHandler(active + 1);   };


backHandler = () => {
let active = this.state.active;
this.setState({
active: active - 1
});
this.props.pageHandler(active - 1);   };


renderPageNumbers = (pageNumbers, totalPages) => {
let { active } = this.state;
return (
<Pagination>
<Pagination.Prev disabled={active < 5} onClick={ active >5 && this.backHandler} />


{
pageNumbers.map(number => {
if (
number >= parseInt(active) - 3 &&
number <= parseInt(active) + 3
) {
return (
<Pagination.Item
id={number}
active={number == active}
onClick={this.pagingHandler}
>
{number}
</Pagination.Item>
);
} else {
return null;
}
})}
<Pagination.Next onClick={ active <= totalPages -4 && this.nextHandler} />
</Pagination>
);   };


buildComponent = (props, state) => {
const { totalPages } = props;
const pageNumbers = [];
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(i);
}
return (
<div className="pull-right">
{this.renderPageNumbers(pageNumbers ,totalPages)}
</div>
);
};


render() {
return this.buildComponent(this.props, this.state);
}


}
PaginationHandler.propTypes =
{
paging: PropTypes.object,
pageHandler: PropTypes.func,
totalPages: PropTypes.object
};

在父组件中使用以上子组件,如下所示

import Pagination from "../pagination";


pageHandler = (offset) =>{
this.setState(({ paging }) => ({
paging: { ...paging, offset: offset }
}));
}
render() {
return (
<div>
<Pagination
paging = {paging}
pageHandler = {this.pageHandler}
totalPages = {totalPages}>
</Pagination>
</div>
);
}
     

一个 ReactJS 哑组件来呈现分页。你也可以使用这个库:

https://www.npmjs.com/package/react-js-pagination

以下是一些例子:

Http://vayser.github.io/react-js-pagination/

或者

你也可以使用这个 https://codepen.io/PiotrBerebecki/pen/pEYPbY

确保它作为一个单独的组件 我曾经使用过 < a href = “ http://tabler-react.com”rel = “ nofollow norefrer”> tabler-response

import * as React from "react";
import { Page,  Button } from "tabler-react";
class PaginateComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
limit: 5, // optional
page: 1
};
}


paginateValue = (page) => {
this.setState({ page: page });
console.log(page) // access this value from parent component
}


paginatePrevValue = (page) => {
this.setState({ page: page });
console.log(page)  // access this value from parent component
}
paginateNxtValue = (page) => {
this.setState({ page: page });
console.log(page)  // access this value from parent component
}


render() {
return (
<div>
<div>
<Button.List>
<Button
disabled={this.state.page === 0}
onClick={() => this.paginatePrevValue(this.state.page - 1)}
outline
color="primary"
>
Previous
</Button>


{this.state.array.map((value, index) => {
return (
<Button
onClick={() => this.paginateValue(value)}
color={
this.state.page === value
? "primary"
: "secondary"
}
>
{value}
</Button>
);
})}


<Button
onClick={() => this.paginateNxtValue(this.state.page + 1)}
outline
color="secondary"
>
Next
</Button>
</Button.List>
</div>
</div>


)
}
}


export default PaginateComponent;

我已经在 ReactJ 中实现了分页 + 搜索,请看输出: 反应中的分页

在 GitHub 上查看完整代码: https://github.com/navanathjadhav/generic-pagination

还可以访问本文,了解分页的分步实现: https://everblogs.com/react/3-simple-steps-to-add-pagination-in-react/

请参见代码和框中的代码示例

Https://codesandbox.io/s/pagino-13pit

enter image description here

import Pagino from "pagino";
import { useState, useMemo } from "react";


export default function App() {
const [pages, setPages] = useState([]);


const pagino = useMemo(() => {
const _ = new Pagino({
showFirst: false,
showLast: false,
onChange: (page, count) => setPages(_.getPages())
});


_.setCount(10);


return _;
}, []);


const hanglePaginoNavigation = (type) => {
if (typeof type === "string") {
pagino[type]?.();
return;
}


pagino.setPage(type);
};


return (
<div>
<h1>Page: {pagino.page}</h1>
<ul>
{pages.map((page) => (
<button key={page} onClick={() => hanglePaginoNavigation(page)}>
{page}
</button>
))}
</ul>
</div>
);
}

1-使用 react-bootstrap

import React from "react";
import { Pagination } from "react-bootstrap";
import Link from "next/link";


interface PaginateProps {
pages: number;
page: number;
keyword?: string;
isAdmin?: boolean;
}


const Paginate = ({
pages,
page,
// keyword is for searching
keyword = "",
isAdmin = false,
}: PaginateProps) => {
return pages > 1 ? (
<Pagination>
{/* keys returns a new Array iterator contians the keys for each index */}
// pages is total number of pages
{[...Array(pages).keys()].map((x) => (
// this is next.js component. you could use react Link
<Link
passHref
key={x + 1}
href={
!isAdmin
// since array indexing starts at 0, use x+1
? `/?keyword=${keyword}&page=${x + 1}`
: `/admin/productlist/?keyword=${keyword}&page=${x + 1}`
}
>
<Pagination.Item active={x + 1 === page}>{x + 1}</Pagination.Item>
</Link>
))}
</Pagination>
) : null;
};


export default Paginate;

然后在页面中使用它。

    <Paginate page={page} pages={pages} keyword={keyword} />

2-use response-js pagination 2-使用 response-js 分页

  import Pagination from "react-js-pagination";


// bootstrap class to center
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={page}
itemsCountPerPage={resPerPageValue}
totalItemsCount={Count}
onChange={handlePagination}
nextPageText={"Next"}
prevPageText={"Prev"}
firstPageText={"First"}
lastPageText={"Last"}
// overwriting the style
itemClass="page-item"
linkClass="page-link"
/>
</div>

OnChange 处理程序

 const handlePagination = (pageNumber) => {
// window.location.href will reload entire page
router.push(`/?page=${pageNumber}`);
};