Paginating the Data
So the concept is that we should add a property showingArr to our state.
showingArr holds the items to be shown according to what pagination page we’re on.
For example, if we’re on page 1, it should show items 1-4
If its page 2, 5-8
page 3, 9-12, and so on.
What we’re interested in is the first and last item #.
The last item # is always the current page * 4.
So if we’re on page 1, the last item is 4, page 2, last item is 8…etc.
so last item is currentPage * 4
The first item will always be last time – 4
Thus, using them, we paginate the movies array like so:
1 2 3 4 5 6 7 8 |
#paginateMovies = (page=1) => { const { pageSize, movies } = this.state; let max = page * pageSize; let min = max - pageSize; let showingArr = [...movies]; // slice returns shallow copy return showingArr.slice(min, max); } |
We create a private function paginateMovies.
In the beginning all the state will be set up when the virtual DOM is being built. When it finishes, it will call render which shows the default state, then in componentDidMount, we will set our state’s showingArr to the correct array. Hence in our componentDidMount():
1 2 3 |
componentDidMount() { this.setState({showingArr: this.#paginateMovies()}); } |
the setState will trigger a second render, which then will show the paginated items.
full source (movies.jsx)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
import React, { Component } from 'react'; import { getMovies } from '../../src/services/fakeMovieService'; import Pagination from './common/pagination'; class Movies extends Component { state = { movies: getMovies(), pageSize: 4, currentPage: 1, showingArr: [], } #paginatedMovies = (page=1) => { const { pageSize, movies } = this.state; let max = page * pageSize; let min = max - pageSize; let showingArr = [...movies]; // slice returns shallow copy return showingArr.slice(min, max); } componentDidMount() { this.setState({showingArr: this.#paginatedMovies()}); } handleDelete = movie => { const movies = this.state.movies.filter(m => m._id !== movie._id); this.setState({movies}); }; handleLike = movie => { } handlePageChange = page => { console.log('you have clicked on page: ', page); // causes new rendering. // whenever we render, currently, we render all movies // what we need to do is to render only certain # of pages // in accordance to our currentPage // we render according to our currentPage // if its currentPage is 1, [1,2,3,4] // if currentPage is [5, 6, 7, 8] this.setState({ currentPage: page, showingArr: this.#paginatedMovies(page) }) } render() { const { length: count} = this.state.movies; const { pageSize, currentPage, showingArr } = this.state; if (count === 0) return <p>No Movies in DB</p>; return ( <React.Fragment> <p>Showing {count} movies in the database.</p> <table className="table"> <thead> <tr> <th>Title</th> <th>Genre</th> <th>Stock</th> <th>Rate</th> <th></th> </tr> </thead> <tbody> {showingArr.map(movie => { return ( <tr key={movie._id}> <td>{movie.title}</td> <td>{movie.genre.name}</td> <td>{movie.numberInStock}</td> <td>{movie.dailyRentalRate}</td> <td><button onClick={() => this.handleDelete(movie)} className="btn btn-danger btn-sm">delete</button></td> </tr> ); })} </tbody> </table> <Pagination itemsCount={count} pageSize={pageSize} currentPage = {currentPage} onPageChange={this.handlePageChange} /> </React.Fragment>) } } export default Movies; |