I am new to ReactJS and am creating a simple TODO application in it. Actually, it is a very basic app with no db connection, tasks are stored in an array. I added Edit and Delete functionality to it now I want to add pagination. How do I implement it? Any help will be appreciated. Thank you...!!
This question is related to
reactjs
pagination
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')
);
I've recently created library which helps to cope with pagination cases like:
DEMO page implements all above features.
Source code you can find on Github
I have implemented pagination + search in ReactJs, see the output: Pagination in React
View complete code on GitHub: https://github.com/navanathjadhav/generic-pagination
Also visit this article for step by step implementation of pagination: https://everblogs.com/react/3-simple-steps-to-add-pagination-in-react/
Give you a pagination component, which is maybe a little difficult to understand for newbie to react
:
I have tried to recreate the simple pagination example given by piotr-berebecki which was great. But when there will be a lot of pages then the pagination will overflow in the screen. So, I used previous and back button along with forward and backward button to stream back and forth between the pages. And for design part I have used bootstrap 3.
You can customize no of pages to display in pagination using the pagebound values. Make sure to use same value for upperPageBound and 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}> … </a></li>
}
let pageDecrementBtn = null;
if(lowerPageBound >= 1){
pageDecrementBtn = <li className=''><a href='#' onClick={this.btnDecrementClick}> … </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')
);
Working demo link : https://codepen.io/mhmanandhar/pen/oEWBqx
Image : simple react pagination
Please see this code sample in codesandbox
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>
);
}
A ReactJS dumb component to render pagination. You can also use this Library:
https://www.npmjs.com/package/react-js-pagination
Some Examples are Here:
http://vayser.github.io/react-js-pagination/
OR
You can also Use this https://codepen.io/PiotrBerebecki/pen/pEYPbY
Make sure you make it as a separate component I have used 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;
Here is a way to create your Custom Pagination Component from react-bootstrap lib and this component you can use Throughout your project
Your Pagination Component (pagination.jsx or 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
};
Use of Above Component in your Component
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>
);
}
I recently created this Pagination component that implements paging logic like Google's search results:
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;
And here's an example App component that uses the Pagination component to paginate a list of 150 example items:
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;
For more details and a live demo you can check out this post
Source: Stackoverflow.com