The object I want to edit gets edited in JSON format, but only previous data gets displayed in the browser. I use these hooks to get a list of products from local storage
const Cart = () => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(()=>{
setProducts(loadCart());
setLoading(false)
},[])
Then I map all of the objects
const mapProducts = (products) => {
return (
<>
{products.map((product) => {
return (
<>
<div className="cart-detail">
<h4>{product.name} - {product.price}$
/ total: {product.price * product.amount}$</h4>
<h4>{product.amount}</h4>
<button onClick={() => incrementAmount(product)}>+</button>
</div>
</>
)
})}
</>
)
}
return (
<Base title="Cart">
{loading && <h1>Loading...</h1>}
{!loading && mapProducts(products)}
</Base>
)
incrementAmount() function looks like that:
const incrementAmount = (product) => {
let tempList = products
for (let i = 0; i < tempList.length; i++) {
if (tempList[i].id === product.id) {
tempList[i].amount++;
}
}
setProducts(tempList)
}
From what I see in the console, the array looks fine and the object I wanted to edit got edited. FE: I had an object {name:"hoodie", amount:3} after clicking "+" button it changes properly to {name:"hoodie", amount:4} (in both products and tempList) but in console only, in the document it still displays product.amount as 3 and I have no idea why
Instead of pass an object to setState you can pass a function and when you have an object into the state that you want to keep old values you must use a function.
Because state may be updated asynchronously, you should not rely on their values for calculating the next state.
You must change the incrementAmount() function like this:
const incrementAmount = (product) => {
setProducts(prevState => {
const newState = [...prevState];
for (let i = 0; i < newState.length; i++) {
if (newState[i].id === product.id) {
newState[i].amount++;
}
}
return newState;
});
}
This is because react triggers a rerender only when the state changes. When you are calling setProducts in incrementAmount, you are essentially passing the same object (with one nested property updated). So react does not register this as a state change. This is due to how objects and arrays work in Javascript.
In order for your code to work, change let tempList = products to let tempList = [...products]. This will create a new object in memory and copy over values from products. And finally when you pass this to setProducts, a rerender will be triggered updating your HTML.