I have the following component in React:
import React, { useState, useEffect } from 'react';
import api from '../../services/api';
const Store = () => {
const [products, setProducts] = useState([]);
let pagination = null;
const getProducts = async (page = 1) => {
const { data } = await api.get('products', { params: { page } });
setProducts([...products, ...data.products]);
pagination = data.pagination;
if (pagination.current < pagination.max) {
document.addEventListener('scroll', loadMore);
}
};
const loadMore = () => {
const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 300) {
getProducts(pagination.current + 1);
document.removeEventListener('scroll', loadMore);
}
};
useEffect(() => {
getProducts();
}, []);
useEffect(() => {
console.log(products);
}, [products]);
return (
<div>
{products.map(product => (
<p>{product.name}</p>
))}
</div>
);
};
export default Store;
My console.log inside the useEffect hook do print the products array correctly, and the component is also rendering the products titles correctly.
But when I try to access the products variable inside the getProducts function it doesn't get the updated products value, it gets the value I have set in the useState hook.
For example, if I start the state with one product, calling products within the getProducts function will always bring this one product, and not the ones loaded from the API fetch, that were correctly logged in the console.
So, when I try to add more products to the end of the array it actually just add the products to an empty array.
Any idea why this is happening? Being able to access the products state inside the useState hook but not inside the getProducts function?
productsstate won't be altered until the next render aftersetProductsis run. Within yourgetProductsfunction you need to usedata.productsto access the new values. Perhaps create a temp variable likeconst tempProducts = [...products, ...data.products];and then usetempProductsto update the statesetProducts(tempProducts);and also usetempProductsanywhere you need to access the updated value withingetProducts....productswill bring me nothing, so I end up only with the fetched products. The solution I found was to set the state in thegetProductsfunction likesetProducts(previousProducts => ([...previousProducts, ...data.products])). It did work, but I still don't understand why theproductsvariable is empty, even after theconsole.log(products)has showed me that the state was updated.productsafter the state finishes updating, as all the products are already being showed in the browser when theloadMorecalls thegetProductsagain.