如何在 React 中实现分页

Posted

技术标签:

【中文标题】如何在 React 中实现分页【英文标题】:How to implement pagination in React 【发布时间】:2017-03-07 01:58:48 【问题描述】:

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

如何实现它?任何帮助将不胜感激。谢谢...!!

【问题讨论】:

可以在 Github 中搜索关键字reactjs todo。你会得到很多样本。我建议你先研究它们 是的,我提到了上述功能。但是对于分页,我没有找到任何帮助。 [反应分页] (github.com/AdeleD/react-paginate) 我在纯 reactjs 中创建了分页:***.com/questions/51982376/… 【参考方案1】:

这是一种从 react-bootstrap 库创建自定义分页组件的方法,您可以在整个项目中使用该组件

您的分页组件(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>
    );
  
     

【讨论】:

我的表项在我的表区域中没有变化?【参考方案2】:

请在codeandbox中查看此代码示例

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

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

【讨论】:

【参考方案3】:

我已经在 ReactJs 中实现了分页+搜索,看输出: Pagination in React

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

分页的分步实现也可以看这篇文章:https://everblogs.com/react/3-simple-steps-to-add-pagination-in-react/

【讨论】:

【参考方案4】:

确保将其作为单独的组件 我用过tabler-react

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;

【讨论】:

【参考方案5】:

一个用于渲染分页的 ReactJS 哑组件。你也可以使用这个库:

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

这里有一些例子:

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

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

【讨论】:

【参考方案6】:

我尝试重新创建piotr-berebecki 给出的简单分页示例,这很棒。但是当页面很多时,分页就会在屏幕上溢出。因此,我使用了前后按钮以及前进和后退按钮在页面之间来回播放。对于设计部分,我使用了 bootstrap 3。

您可以使用 pagebound 值自定义要在分页中显示的页面数量。确保对 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

图片:simple react pagination

【讨论】:

工作就像一个魅力【参考方案7】:

我最近创建了有助于处理分页情况的库,例如:

在 Redux 中存储标准化数据 根据搜索过滤器缓存页面 简化反应虚拟化列表用法 在后台刷新结果 存储上次访问的页面和使用的过滤器

DEMO页面实现了以上所有功能。

你可以在Github找到源代码

【讨论】:

【参考方案8】:
   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')
    );

【讨论】:

【参考方案9】:

我最近创建了这个分页组件,它实现了类似于 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;

欲了解更多详情和现场演示,您可以查看this post

【讨论】:

使用npmjs.com/package/react-js-pagination之类的东西而不是重新发明***不是更好吗? @Jason 我在 git repo 上提出了你的实现中的一个问题,你能看看吗? github.com/cornflourblue/react-pagination-example/issues/8【参考方案10】:

我最近在纯 React JS 中实现了分页。这是一个工作演示:http://codepen.io/PiotrBerebecki/pen/pEYPbY

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

完整代码:

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

【讨论】:

谢谢你,Piotr Berebecki。这真的是最简单和最好的答案.. 非常感谢...!!! 另一个在 React 中构建分页列表的动手教程:robinwieruch.de/react-paginated-list 超出预期:) 我不明白在调用 handleClick 方法后如何重新加载元素列表?我正在尝试刷新列表而不重新加载页面。非常感谢。 看这里:hemanta.io/…【参考方案11】:

给你一个分页组件,新手可能有点难以理解react

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

【讨论】:

是的..对于新手来说有点困难。无论如何感谢您的帮助..:-)

以上是关于如何在 React 中实现分页的主要内容,如果未能解决你的问题,请参考以下文章

如何在nodejs + postgresql中实现分页

如何在 dojox.datagrid 中实现分页

如何在排名查询中实现分页?

如何在 PHP 中实现分页? [关闭]

如何在 Git 标签中实现分页

如何在Android listview中实现分页