Reusable React Pagination Component
I am trying to create dynamic pagination react component with reactstrap
as UI library. I am stuck around the problem of completing the same.
UsersCard.js
import React, { Component } from 'react'
import axios from 'axios';
import PaginationTable from './PaginationTable';
export default class UsersCard extends Component {
constructor(props) {
super(props)
this.state = {
usersData: [],
loading: false,
per_page: 3,
current_page: 1,
total_data: '',
currentPosts: []
}
}
async componentDidMount(){
await axios.get('https://reqres.in/api/users')
.then(res => {
this.setState({
usersData: res.data.data,
loading: false,
total_data: res.data.data.length
})
})
.catch(err => console.log(err));
const indexOfLastPost = this.state.current_page * this.state.per_page;
const indexOfFirstPage = indexOfLastPost - this.state.per_page;
const currentPosts = this.state.usersData.slice(indexOfFirstPage, indexOfLastPost);
this.setState({ currentPosts })
}
handleClick = (number) => {
this.setState({
current_page: number
})
}
render() {
const { per_page, handleClick, total_data, current_page, currentPosts } = this.state;
return (
<div>
<table>
<thead>
<tr>
<th>Id</th>
<th>First Name</th>
<th>email</th>
<th>Last Name</th>
</tr>
</thead>
{currentPosts.map(x => {
return(
<React.Fragment key={x.id}>
<tbody>
<tr>
<td>{x.id}</td>
<td>{x.first_name}</td>
<td>{x.email}</td>
<td>{x.last_name}</td>
</tr>
</tbody>
</React.Fragment>
)
})}
</table>
<PaginationTable
per_page={per_page}
current_page={current_page}
total_data={total_data}
handleClick={handleClick}
/>
</div>
)
}
}
PaginationTable.js
import React from 'react';
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
const PaginationTable = ({ per_page, total_data, handleClick, current_page }) => {
let pageNumbers = [];
for(let i=1; i<= Math.ceil(total_data/per_page); i++)
{
pageNumbers.push(
<PaginationItem key={i} active={current_page === i ? true : false}>
<PaginationLink onClick={() => handleClick(i)} target="_blank" rel="nofollow noreferrer" href="#">
{i}
</PaginationLink>
</PaginationItem>)
}
return(
<Pagination aria-label="Page navigation example">
<PaginationItem disabled={current_page <= 1}>
<PaginationLink onClick={()=>handleClick(current_page-1)}
previous
target="_blank" rel="nofollow noreferrer" href="#"
/>
</PaginationItem>
{pageNumbers}
<PaginationItem disabled={current_page >= per_page - 1}>
<PaginationLink onClick={()=>handleClick(current_page + 1)}
next
target="_blank" rel="nofollow noreferrer" href="#"
/>
</PaginationItem>
</Pagination>
)
}
export default PaginationTable;
My problems go like:
1) Reactstrap pagination UI is not showing properly.
2) Whenever I click on the next
button, it consoles the error: TypeError: handleClick is not a function
.
I am bit new to the dynamic pagination concept and am unable to identify the bug I am stuck with. Kindlt help to resolve the same. Any code improvements are also welcomed.
Answer
There are multiple problems with this approach:
this.handleClick
has to be passed in from the parent.setState
function is asynchronous. So accessing the state right after setting it might not result in the same state you wish. To get around this React gives you a callback function as second argument. This is run only after the state is run.You are not updating the
currentPosts
state after change in pagination. Pagination component is only concerned with changing page numbers, the change in data has to manually handled. You can handle this with:
async componentDidMount() {
await axios
.get("https://reqres.in/api/users")
.then(res => {
this.setState({
usersData: res.data.data,
loading: false,
total_data: res.data.data.length
}, () => {
this.formatData();
});
})
.catch(err => console.log(err));
}
formatData() {
const indexOfLastPost = this.state.current_page * this.state.per_page;
const indexOfFirstPage = indexOfLastPost - this.state.per_page;
const currentPosts = this.state.usersData.slice(
indexOfFirstPage,
indexOfLastPost
);
this.setState({ currentPosts });
}
handleClick = number => {
this.setState({
current_page: number
}, () => {
this.formatData();
});
};
Related Questions
- → How to update data attribute on Ajax complete
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → Octobercms Component Unique id (Twig & Javascript)
- → Passing a JS var from AJAX response to Twig
- → Laravel {!! Form::open() !!} doesn't work within AngularJS
- → DropzoneJS & Laravel - Output form validation errors
- → Import statement and Babel
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM