I’m working on creating a shopping cart. The cart itself (the list of all items in the cart) is a component and each cart item is a component. In each cart item, there’s a dropdown list to change the quantity of that item you’d like to buy (1-5). There is also an X button that will remove that item from the cart. The X button (removing the item) works just fine. Here’s the code for that:
function removeItem(id) {
const newCart = cart.filter((item) => item.id !== id)
setCart(newCart);
}
This is how I’m removing an item from the cart (creating a newCart
variable and using setCart(newCart)
to update that. This code, again, works just fine and the cart item is removed from the user’s screen.
However, I’m trying to incorporate a similar approach to adjusting the quantity of an item. When I run the code below, however, the visual updates are not happening. However, when I console.log()
the cart
variable, the updates are shown there. Here is the code I have for that:
function changeQuantity(event, id) {
let newCart = cart;
for (let i=0; i<cart.length; i++) {
if (cart[i].id === id) {
newCart[i].quantity = parseInt(event.target.value); // update quantity
newCart[i].name = "CHANGED"; // debugging purposes, to know if it was changed
}
}
setCart(newCart); // this doesn't seem to change the cart visually
console.log(cart); // but in the console I can see the changes being made
}
For some reason, when I go into the console, I can see the changes being made (the price is adjusted to the correct quantity, and the name of the item is "CHANGED"); but visually in the cart, this change is not shown. The removal of an item works fine, but using the same approach is not working to adjust the quantity.
I’m not sure where the logic is going wrong here, so any help is appreciated.
EDIT: Something interesting that happens is that when I save the code and the page is re-rendered, everything is updated accordingly, even it wasn’t before.
2
Answers
React operates under the assumption that state is immutable. This makes it very quick for react to check whether the state has changed, because it just needs to do a single Object.is check (similar to
===
).In your code, you are mutating the cart object, then calling setCart with the mutated object. React compares the old object with the new object using
Object.is
, and sees that they are the same object. As such, it appears nothing has changed and react does not rerender.Instead, you must make a new state. For example:
PS:
cart
is the old state, not the new state. So the reason you’re seeing the changes is that you’re mutating the old state. If you’re doing things correctly, this log statement should show no change.In your changeQuantity function, you’re directly mutating the cart state object, which can lead to unexpected behavior in React
Why Update Fails
Solution:
To correctly update the state and ensure React re-renders your component with the updated quantity, you should create a new array and objects for any changed items. Here’s how you can refactor your changeQuantity function.