46
loading...
This website collects cookies to deliver better user experience
const totalPages = dataset.length / contentPerPage
// totalPages = 3
Array.slice( )
method to the rescue!slice()
method returns a shallow copy or a portion of an array into a new array object selected from start to end (it is important to note the end is not included) where start and end represent the index of items in that array. The original array will not be modified.const footballClubs = ["liverpool","chelsea", "manUtd","arsenal", "manCity", "spurs", "westHam", "everton", "cardiff"];
footballClubs.slice(2,5)
// output: [ "manUtd","arsenal", "manCity"]
footballClubs.slice(1,3)
// output : ["chelsea", "manUtd"]
currentPage
( the page we are on) value to slice the data which means getting startIndex
and lastIndex
based on the value of currentPage
.// initial load . Should start with 1st page
const page = 1;
// our desired amount of contenct we would like to display
const contentPerPage = 3
const lastIndex = page * contentPerPage // 3
const firstIndex = lastIndex - contentPerPage // 0
footballClubs.slice(firstIndex, lastIndex)
// footballClubs.slice(0, 3) => ["liverpool","chelsea", "manUtd" ]
// page 2
// footballClubs.slice(3, 6) => [ "arsenal", "manCity", "spurs" ]
currentPage
state variable. (on the initial load it will be set to 1 we explain why above).<CharacterGrid>
component takes care of displaying the content based on currentPage and <Pagination>
component takes care of page buttons and changing currentPage state variable. It is as mentioned above very simple implementation.App Component
looks like👇//App.js
import React, { useState, useEffect } from "react";
import "./App.css";
import Header from "./components/UI/Header";
import CharacterGrid from "./components/characters/CharacterGrid";
import Search from "./components/UI/Search";
import Pagination from "./components/pagination/Pagination";
import Spinner from "./components/UI/Spinner";
//👇 my custom data fetch hook
import { useDataFetch } from "./useDataFetch";
const App = () => {
const [query, setQuery] = useState("");
// 💥 this is our ever so important state variable.On initial load is set to !
const [currentPage, setCurrentPage] = useState(1);
// 💥 V2 👇 V2 version2 of implementing change of
//current items using useEffect instead of mine original one
// const [currentItems, setCurrentItems] = useState([]);
//💥 this predefined contentPerPage we would like to display
const [itemsPerPage] = useState(8);
const [{ items, isLoading, isError, search }, setSearch] =
useDataFetch(query);
const handleChange = (q) => {
setQuery(q);
};
const handleSearch = () => {
setSearch(query);
setCurrentPage(1);
setQuery("");
};
//💥 V2 👇
// useEffect(() => {
// const indexOfLastItem = currentPage * itemsPerPage; // 8
// const indexOfFirstItem = indexOfLastItem - itemsPerPage; // 0
// setCurrentItems(items.slice(indexOfFirstItem, indexOfLastItem)); // items.slice(8,16)
// }, [currentPage, items, itemsPerPage]);
// Get current posts
//💥 This our slicing implementation in practice
// V2 👆 you can use useEffect hook instead of this implementation
const indexOfLastItem = currentPage * itemsPerPage; // 8
const indexOfFirstItem = indexOfLastItem - itemsPerPage; // 0
const currentItems = items.slice(indexOfFirstItem, indexOfLastItem); // items.slice(0,8)
// Change page
// 💥 this the state setter which will change current page variable and cause re render. it is passed as a prop to Pagination component so whenever button is click will trigger this state setter and cause re-render
const paginate = (pageNumber) => setCurrentPage(pageNumber);
return (
<div className="container">
<Header />
<Search
handleChange={handleChange}
handleSearch={handleSearch}
inputText={query}
/>
{isError && <div> Something went wrong ...</div>}
{isLoading ? (
<Spinner />
) : (
<>
<CharacterGrid items={currentItems} />
<Pagination
itemsPerPage={itemsPerPage}
totalItems={items.length}
paginate={paginate}
currentPage={currentPage}
/>
</>
)}
</div>
);
};
export default App;
Character Component
( a child Component of our Character Grid
) implementation is simple, it just receives currentItems as a prop and renders a simple list item. Pagination Component
looks like this👇//Pagination.js
import React from "react";
const Pagination = ({ itemsPerPage, totalItems, paginate, currentPage }) => {
//💥 simple loop which generates all the potential page number button. Use can use different method such as Array fill() .Important bit here is using Math.ceil. Assume we have 9 item in totalItems and we want to display 4 itemsPerPage => it will generate 3 pages 2 pages with 4 itemsPerPage and 1 with only one.
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(totalItems / itemsPerPage); i++) {
pageNumbers.push(i);
}
return (
<nav>
<ul className="pagination">
{/* 💥 little conditional clause for only displaying the buttons if total number of pages is bigger than 1 */}
{pageNumbers.length > 1
? pageNumbers.map((number) => (
<li
key={number}
{/* 💥 little UX touch to indicate currentPage by giving it active class */}
className={`page-item ${
currentPage === number ? "active" : null
}`}
>
<a
{/* 💥 as mentioned previously important state setter handler. Onclick will change currentPage state variable by using paginate function we passed to this component. */}
onClick={() => paginate(number)}
href="!#"
className="page-link"
>
{number}
<sup>{number}</sup>
</a>
</li>
))
: null}
</ul>
</nav>
);
};
export default Pagination;