const propTypes = {
items: React.PropTypes.array.isRequired,
onChangePage: React.PropTypes.func.isRequired,
initialPage: React.PropTypes.number
}
const defaultProps = {
initialPage: 1
}
class Pagination extends React.Component {
constructor(props) {
super(props);
this.state = { pager: {} };
}
componentWillMount() {
if (this.props.items && this.props.items.length) {
this.setPage(this.props.initialPage);
}
}
componentDidUpdate(prevProps, prevState) {
if (this.props.items !== prevProps.items) {
this.setPage(this.props.initialPage);
}
}
setPage(page) {
var items = this.props.items;
var pager = this.state.pager;
if (page < 1 || page > pager.totalPages) {
return;
}
pager = this.getPager(items.length, page);
var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
this.setState({ pager: pager });
this.props.onChangePage(pageOfItems);
}
getPager(totalItems, currentPage, pageSize) {
currentPage = currentPage || 1;
pageSize = pageSize || 10;
var totalPages = Math.ceil(totalItems / pageSize);
var startPage, endPage;
if (totalPages <= 10) {
startPage = 1;
endPage = totalPages;
} else {
if (currentPage <= 6) {
startPage = 1;
endPage = 10;
} else if (currentPage + 4 >= totalPages) {
startPage = totalPages - 9;
endPage = totalPages;
} else {
startPage = currentPage - 5;
endPage = currentPage + 4;
}
}
var startIndex = (currentPage - 1) * pageSize;
var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
var pages = [...Array((endPage + 1) - startPage).keys()].map(i => startPage + i);
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;
if (!pager.pages || pager.pages.length <= 1) {
return null;
}
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 = defaultProps;
class App extends React.Component {
constructor() {
super();
var exampleItems = [...Array(150).keys()].map(i => ({ id: (i+1), name: 'Item ' + (i+1) }));
this.state = {
exampleItems: exampleItems,
pageOfItems: []
};
this.onChangePage = this.onChangePage.bind(this);
}
onChangePage(pageOfItems) {
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/post/2017/03/14/react-pagination-example-with-logic-like-google" target="_top">React - Pagination Example with Logic like Google</a>
</p>
<p>
<a href="http://jasonwatmore.com" target="_top">JasonWatmore.com</a>
</p>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
View Compiled