web-dev-qa-db-fra.com

comment implémenter la pagination dans les réactions

Je suis nouveau sur ReactJS et je crée une application TODO simple. En fait, c'est une application très basique sans connexion à la base de données, les tâches sont stockées dans un tableau. J'y ai ajouté les fonctionnalités d'édition et de suppression et je souhaite maintenant ajouter une pagination. Comment puis-je le mettre en œuvre? Toute aide serait appréciée. Je vous remercie...!!

21
Nitesh

J'ai récemment implémenté la pagination dans React JS pur. Voici une démo de travail: http://codepen.io/PiotrBerebecki/pen/pEYPbY

Vous devrez bien entendu ajuster la logique et la manière dont les numéros de page sont affichés pour répondre à vos besoins.

Code complet:

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')
);
63
Piotr Berebecki

J'ai essayé de recréer l'exemple de pagination simple donné par piotr-berebecki qui était génial. Mais quand il y aura beaucoup de pages, la pagination débordera à l'écran. J'ai donc utilisé les boutons précédent et précédent ainsi que les boutons avant et arrière pour naviguer entre les pages. Et pour la conception, j’ai utilisé bootstrap 3. 

Vous pouvez personnaliser le nombre de pages à afficher dans la pagination à l'aide des valeurs liées aux pages. Assurez-vous d'utiliser la même valeur pour upperPageBound et 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')
        );

Lien de démonstration: https://codepen.io/mhmanandhar/pen/oEWBqx

Image: pagination simple react

1
Mahesh Manandhar
   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')
    );
1

J'ai récemment créé ce composant Pagination qui implémente une logique de pagination similaire aux résultats de recherche de 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;

Et voici un exemple de composant d'application qui utilise le composant Pagination pour paginer une liste de 150 exemples d'éléments:

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;

Pour plus de détails et une démonstration en direct, vous pouvez consulter cet article

1
Jason

Voici un moyen de créer votre composant de pagination personnalisée à partir de react-bootstrap lib et ce composant que vous pouvez utiliser tout au long de votre projet  enter image description here

Votre composant de pagination (pagination.jsx ou 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 
   };

Utilisation du composant ci-dessus dans votre composant

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>
    );
  }
0
Ameya Salagre

Un composant muet ReactJS pour rendre la pagination. Vous pouvez également utiliser cette bibliothèque:

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

Quelques exemples sont ici: 

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

OU 

Vous pouvez également utiliser ceci https://codepen.io/PiotrBerebecki/pen/pEYPbY

0
Vishal Thakur

J'ai récemment créé une bibliothèque qui aide à gérer les cas de pagination tels que:

  • stocker des données normalisées dans Redux
  • la mise en cache des pages en fonction des filtres de recherche
  • utilisation simplifiée de la liste de réactions et virtualisation
  • résultats rafraîchissants en arrière-plan
  • stocker la dernière page visitée et les filtres utilisés 

DEMO page implémente toutes les fonctionnalités ci-dessus.

Le code source que vous pouvez trouver sur Github

0
Andrzej