0

So I’m having a little trouble on loading more items from the array. I already made it display the first four items, but when I click the Pagination items it doesn’t show me the next items. I’m using the Pagination component from React Bootstrap, since it’s the main framework of my project.

  const [pagination, setPagination] = useState({
    data: names,
    offset: 0,
    numberPerPage: 4,
    pageCount: 0,
    currentData: [],
    activePage: 1
  });

  useEffect(() => {
    setPagination((prevState) => ({
      ...prevState,
      pageCount: prevState.data.length / prevState.numberPerPage,
      currentData: prevState.data.slice(
        pagination.offset,
        pagination.offset + pagination.numberPerPage
      )
    }));
  }, [pagination.numberPerPage, pagination.offset]);

  const handlePageClick = (event) => {
    const selected = event.selected;
    const offset = selected * pagination.numberPerPage;
    const activePage = selected + 1;
    setPagination({ ...pagination, offset, activePage });
  };

  // Pagination items
  const paginationItems = [];
  const amountPages = pagination.data.length / pagination.numberPerPage;
  for (let number = 1; number <= amountPages; number++) {
    paginationItems.push(
      <Pagination.Item
        onClick={handlePageClick}
        key={number}
        active={number === pagination.activePage}
      >
        {number}
      </Pagination.Item>
    );
  }

  return (
    <div className="list">
      <Container>
        {pagination.currentData &&
          pagination.currentData.map((item, index) => (
            <div key={index} className="post">
              <h3>{item.name}</h3>
            </div>
          ))}

        <Pagination>{paginationItems}</Pagination>
      </Container>
    </div>
  );

Here is the codesandbox that I'm using for example: https://codesandbox.io/s/react-bootstrap-pagination-mp9l8?file=/src/App.js

1 Answer 1

1

when you have an object as a state, you should change state with useReducer. first of all you should set Onclick on Pagination component instead of Pagonation.Item, also I set data-page attribute for each Pagination.Item for access that on handleClick function.

import React, { useReducer, useEffect } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Container, Pagination } from "react-bootstrap";

export default function App({ content }) {

  const reducer = (state, action) => {
    switch (action.type) {
      case "setPageCount":
        return { ...state, pageCount: action.payload };
      case "setCurrentData":
        return { ...state, currentData: action.payload };
      case "setOffset":
        return { ...state, offset: action.payload };
      case "setActivePage":
        return { ...state, activePage: action.payload };
      default:
        throw new Error();
    }
  };

  const initialState = {
    data: names,
    offset: 0,
    numberPerPage: 4,
    pageCount: 0,
    currentData: [],
    activePage: 1
  };

  const [state, dispatch] = useReducer(reducer, initialState);

  useEffect(() => {
    dispatch({
      type: "setCurrentData",
      payload: state.data.slice(
        state.offset,
        state.offset + state.numberPerPage
      )
    });
  }, [state.numberPerPage, state.offset]);

  const handleClick = (e) => {
    const clickValue = parseInt(e.target.getAttribute("data-page"), 10);
    dispatch({
      type: "setOffset",
      payload: (clickValue - 1) * state.numberPerPage
    });
    dispatch({
      type: "setActivePage",
      payload: clickValue
    });
    dispatch({
      type: "setPageCount",
      payload: state.data.length / state.numberPerPage
    });
  };

  // Pagination numbers
  const paginationItems = [];
  const amountPages = state.data.length / state.numberPerPage;
  for (let number = 1; number <= amountPages; number++) {
    paginationItems.push(
      <Pagination.Item
        key={number}
        active={number === state.activePage}
        data-page={number}
      >
        {number}
      </Pagination.Item>
    );
  }

  return (
    <div className="list">
      <Container>
        {state.currentData &&
          state.currentData.map((item, index) => (
            <div key={index} className="post">
              <h3>{item.name}</h3>
            </div>
          ))}

        <Pagination onClick={handleClick}>{paginationItems}</Pagination>
      </Container>
    </div>
  );
}

you can see how it's work HERE

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your explanation. I’m new on React, so I’ve never used useReducer before. On the documentation, it says that useReducer has better performance and it's better for complex states. I’ve eventually managed to get the same result using useState, but because of its benefits I will stick with your solution. Very thanks.
I’ve edited your answer just to add a Math.ceil to the amount of items where it’s generated the pagination. Because if the state.data.length / state.numberPerPage gives me a number with decimals, it doesn’t display the last page. So it needs to be rounded up first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.