Search code examples
reactjsreact-hookspaginationuse-effect

Number of current page doesnt change in react


I am using react-paginate (https://www.npmjs.com/package/react-paginate) to make pagination for my app. Everything is fine but I cannot increase the current number of the page. So for this here is my parent component:

import React, { useEffect, useState } from "react";
import Product from "../components/sub-components/Product";
import SimpleBox from "../components/sub-components/SimpleBox";
import BoxWithSearch from "../components/sub-components/BoxWithSearch";
import LoadingBox from "../components/sub-components/LoadingBox";
import MessageBox from "../components/sub-components/MessageBox";
import Cart from "../components/sub-components/Cart";
import { useDispatch, useSelector } from "react-redux";
import { listProducts } from "../actions/productActions";
import ReactPaginate from "react-paginate";

export default function HomeScreen() {
  const dispatch = useDispatch();
  const productList = useSelector((state) => state.productList);
  const { loading, error, products } = productList;
  const [currentPage, setCurrentPage] = useState(1);
  const [pageCount, setpageCount] = useState(0);

  useEffect(() => {
    dispatch(listProducts(currentPage));
    console.log(currentPage);
  }, [dispatch]);

  const handlePageClick = (data) => {
    setCurrentPage(data.selected + 1);
    // scroll to the top
    //window.scrollTo(0, 0)
  };
  return (
    <div className="container">
      <div className="row">
        <div className="col-lg-6 col-md-12 col-sm-12 col-xs-12">
          <h2 className="title">Products</h2>
          <div className="product-type-filter">
            <button>Mug</button>
            <button className="clicked">Shirt</button>
          </div>
          <div className="products">
            <div className="row">
              <div>
                {loading ? (
                  <LoadingBox></LoadingBox>
                ) : error ? (
                  <MessageBox variant="danger">{error}</MessageBox>
                ) : (
                  <div className="row center">
                    {products.map((product) => (
                      <Product key={product.added} product={product}></Product>
                    ))}
                  </div>
                )}
              </div>
            </div>
          </div>
          <ReactPaginate
            previousLabel={"Prev"}
            nextLabel={"Next"}
            pageCount={40}
            marginPagesDisplayed={4}
            pageRangeDisplayed={1}
            onPageChange={handlePageClick}
            containerClassName={"pagination justify-content-center"}
            pageClassName={"page-item"}
            pageLinkClassName={"page-link"}
            previousClassName={"page-item"}
            previousLinkClassName={"page-link"}
            nextClassName={"page-item"}
            nextLinkClassName={"page-link"}
            breakClassName={"page-item"}
            breakLinkClassName={"page-link"}
            activeClassName={"active"}
          />
        </div>
      </div>
    </div>
  );
}

And my action for fetching the data:

import Axios from 'axios';
import {
  PRODUCT_LIST_FAIL,
  PRODUCT_LIST_REQUEST,
  PRODUCT_LIST_SUCCESS,
} from '../constants/productConstants';

export const listProducts = () => async (dispatch, currentPage) => {
  dispatch({
    type: PRODUCT_LIST_REQUEST,
  });
  try {
    const { data } = await Axios.get(`http://localhost:3000/items?_page=${currentPage}&_limit=16`);
    dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
  } catch (error) {
    dispatch({ type: PRODUCT_LIST_FAIL, payload: error.message });
  }
};

But the problem is since the currentPage doesn't change, I cannot go to the other page. Do you have a solution for this? Thanks...


Solution

  • If you are updating the current page and wanting to fetch new data then you might want to add currentPage to the useEffect dependency array so the next current page of products is fetched/listed.

    useEffect(() => {
      dispatch(listProducts(currentPage));
      console.log(currentPage);
    }, [currentPage, dispatch]);
    

    Update

    When I write console.log(currentPage) in action, I am getting this: ƒ getState() { var state = unliftState(liftedStore.getState()); if (state !== undefined) { lastDefinedState = state; } return lastDefinedState; } How can I pass the currentpage number into action?

    In thunks, the second argument is the getState function to be called and get the current redux state. Your listProducts action creator is naming the getState callback currentPage. Also, any arguments being passed to listProducts are being ignored (note the empty arg list in the outer function).

    export const listProducts = () => async (dispatch, currentPage) => {
      dispatch({
        type: PRODUCT_LIST_REQUEST,
      });
      try {
        const { data } = await Axios.get(`http://localhost:3000/items?_page=${currentPage}&_limit=16`);
        dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
      } catch (error) {
        dispatch({ type: PRODUCT_LIST_FAIL, payload: error.message });
      }
    };
    

    listProducts needs to consume the passed currentPage argument in the outer functions, and enclose it in function scope.

    export const listProducts = (currentPage) => async (dispatch) => {
      dispatch({
        type: PRODUCT_LIST_REQUEST,
      });
      try {
        const { data } = await Axios.get(`http://localhost:3000/items?_page=${currentPage}&_limit=16`);
        dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
      } catch (error) {
        dispatch({ type: PRODUCT_LIST_FAIL, payload: error.message });
      }
    };