0
const [cartItems, setcartItems] = useState([] as Product[]);

const addItemToCart = (product: Product) => {
  setcartItems((preCartItems) => {
    const updatedcart = [...preCartItems];
    if(!updatedcart.length)
      updatedcart.push(product)
    // updatedcart[0].price original value 1
    updatedcart[0].price = updatedcart[0].price + 1 ;
    console.log(updatedcart[0].price); // prints 2
    console.log(updatedcart); // printed object is saying price value 3
    return updatedcart;
  });
};

I am unable to understand how the value is incremented automatically by 1 and why is the value on the object giving a different output compared to the value accessed by the dot operator

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
dj43
  • 73
  • 1
  • 11
  • 1
    In development mode the function will be called twice. React does this to check for problems with the code. This leads to some surprising effects, like in this case the product price gets incremented two times. – super Jan 10 '22 at 19:37
  • 1
    You also may be running into console.log's lazy eval of objects which can be confusing when using it to debug objects. https://stackoverflow.com/q/4057440/1309377 – Andrew Lohr Jan 10 '22 at 19:46
  • 1
    I think the answer is a combination of all three contributions here. `StrictMode` causes the setState callback to be executed twice (@super). The OP is mutating state, leading to the additional increment on the second call (@shidoro). And the lazy evaluation of objects passed to console logs (@andrew) causes the discrepancy between the first and second log. – Brian Thompson Jan 10 '22 at 20:29
  • Ultimately the takeaway is, don't mutate state. If the callback obeys this rule, it could be called 10 times and still set the state to the correct value. – Brian Thompson Jan 10 '22 at 20:30

1 Answers1

3

The problem is that you're mutating your state within the setcartItems.

Doing const updatedcart = [...preCartItems]; is not copying the objects in preCartItems, it's just spreading the reference of the same objects in a new array.

Then you're mutating the object here updatedcart[0].price = updatedcart[0].price + 1 ;.

This will lead to two different versions of the state, hence the inconsistent result.

If you want to copy the objects you should do

const updatedcart = preCartItems.map(item => ({ ...item }));

This returns a new array of new objects and you can do any operation you want on them. This way of copying an array of objects is also shallow, it only works for 1 depth level, if you want to copy also nested objects you need a more robust function.

shidoro
  • 362
  • 4
  • 9