So I am working on an online shop as a practice I have imported products data and wanna make pagination. On a page it will be 12 products like so
I have this kind of code, but I don't understand why there is an infinite loop in useEffect and how to fix this The error is: "Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render." I can rid of products in dependancy, but not sure it's the way
import React, {useState, useEffect} from "react";
import data from './products.json'
import Product from "./components/Product/Product";
const PRODUCTS_PER_PAGE = 12
export const Shop = () => {
const [products, setProducts] = useState(data.products)
const [currentPage, setCurrentPage] = useState(1)
const firstIndex = (currentPage - 1) * PRODUCTS_PER_PAGE
const lastIndex = firstIndex PRODUCTS_PER_PAGE
const totalPages = products.length / PRODUCTS_PER_PAGE
useEffect(() => {
const slicedProducts = products.slice(firstIndex,lastIndex)
setProducts(slicedProducts)
console.log(slicedProducts)
}, [currentPage, products])
return (
<div className="products">
{
products.map((product) => (
<Product product={product}/>))
}
</div>
)
}
CodePudding user response:
Remove products
from the dependency array
useEffect(() => {
setProducts(prods => prods.slice(firstIndex,lastIndex))
}, [currentPage])
Edit:
If you want to slice before render, remove useEffect
entirely
import React, {useState, useEffect} from "react";
import data from './products.json'
import Product from "./components/Product/Product";
const PRODUCTS_PER_PAGE = 12
export const Shop = () => {
const [products, setProducts] = useState(data.products)
const [currentPage, setCurrentPage] = useState(1)
const firstIndex = (currentPage - 1) * PRODUCTS_PER_PAGE
const lastIndex = firstIndex PRODUCTS_PER_PAGE
const totalPages = products.length / PRODUCTS_PER_PAGE
return (
<div className="products">
{
products.slice(firstIndex,lastIndex).map((product) => (
<Product product={product}/>))
}
</div>
)
}
CodePudding user response:
You can try using useMemo
// if you dont want to inlcude currentPage as a dependency and trigger another calculation
// const currentPageRef = useRef(currentPage);
// currentPageRef.current = currentPage;
const mappedProducts = useMemo(() => {
const firstIndex = (currentPage - 1) * PRODUCTS_PER_PAGE
const lastIndex = firstIndex PRODUCTS_PER_PAGE
const slicedProducts = products.slice(firstIndex, lastIndex)
return slicedProducts
}, [products, currentPage])
return (
<div className="products">
{
// should this be mappedProducts?.map(product =>
mappedProducts.slice(firstIndex,lastIndex).map((product) => (
<Product product={product}/>))
}
</div>
)
Ideally it could be nice it products could be filtered when making a fetch
Either ways hope this helps you in some way
CodePudding user response:
You have 2 options to fix your issue.
- Holding the previous data for products and currentPage and then compare them to their current value:
import React, {useState, useEffect, useRef} from "react";
import data from './products.json'
import Product from "./components/Product/Product";
const PRODUCTS_PER_PAGE = 12
export const Shop = () => {
const [products, setProducts] = useState(data.products);
const [currentPage, setCurrentPage] = useState(1);
const previousProductsRef = useRef(data.products);
const previousPageRef = useRef(1);
const firstIndex = (currentPage - 1) * PRODUCTS_PER_PAGE
const lastIndex = firstIndex PRODUCTS_PER_PAGE
const totalPages = products.length / PRODUCTS_PER_PAGE
useEffect(() => {
if(JSON.stringify(previousProductsRef.current) !== JSON.stringify(products) || previousPageRef.current !== currentPage) {
const slicedProducts = products.slice(firstIndex,lastIndex);
previousProductsRef.current = slicedProducts;
previousPageRef.current = currentPage;
setProducts(slicedProducts);
console.log(slicedProducts);
}
}, [currentPage, products])
return (
<div className="products">
{
products.map((product) => (
<Product product={product}/>))
}
</div>
)
}
- Using useMemo:
const productsArray = useMemo(() => {
const firstIndex = (currentPage - 1) * PRODUCTS_PER_PAGE;
const lastIndex = firstIndex PRODUCTS_PER_PAGE;
const slicedProducts = products.slice(firstIndex, lastIndex);
return slicedProducts;
}, [currentPage, products]);