Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.5k views
in Technique[技术] by (71.8m points)

javascript - Reducer is adding items in the store out of nowhere

So I am trying to add a cart feauture to my React-redux site and I got stuck on a very weird occurance. So this is what I get from the payload of the action for example:

{
    info: 'Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops',
    id: 1,
    price: 109.95,
    image: 'https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg',
    count: 5,
    totalPrice: 549.75
 }

So what Im trying to do is, when an item with the same id as this one is trying to be added, to not add it, but to increase the count of the item with the same id that already exists in the cart:

const index = state.currentCart.findIndex((x) => x.id === id);
return {
          ...state,
          currentCart: [
            ...state.currentCart,
            state.currentCart[index].count += 1,
             (state.currentCart[index].totalPrice =
              state.currentCart[index].price * state.currentCart[index].count), 
          ],
        };

The count itself is increased, but there is something really strange happening at the same time. The total price of the product and its count are also added as elements of the currentCart array, when the only thing that should happen is to update the count of the cart item with the id from the payload, this is what happens to the currentCart array when this action is fired:

currentCart: [
    {
      info: 'Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops',
      id: 1,
      price: 109.95,
      image: 'https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg',
      count: 6,
      totalPrice: 659.7
    },
    2,
    219.9,
    3,
    329.85,
    4,
    439.8,
    5,
    549.75,
    6,
    659.7
  ]
}

I am sure I am not mutating the state right, thank you in advance!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

No, they are not coming from nowhere, you are actively adding the values to the array. You seem to be a bit confused about how to properly handle states. You either choose an immutable approach (which I really recommend if you are using react) or you choose to mutate your references.

In javascript, when you do an assignment, that assignment also returns the value that is being assigned, so for example here:

let x = 1
let b = x+=1
// b is now 2 and x is 2
let c = b += 2
// b is now 4 and c is also 4

That is exactly what is happening on your array assignment. You are first spreading the old version of the array on the new one (making a copy) and then you mutate the reference to the current car at the same time (and this is the key part) that you are saving the return value of those assignments in the array itself. Take a look at the values on the array, they are the results of your operations:

count (1) += 1 // 2
price (109.95) * count (2) = 219.9,
count (2) += 1 // 3
price (109.95) * count (3) = 329.85
... etc

So what you have on your array is an historic of the count and total price values.

This is a breakdown of what is happening in your code:

// Will allways be at index 0, because you add it as first element 
// and then you keep copying the array below
const index = state.currentCart.findIndex((x) => x.id === id); 
return {
          ...state,
          currentCart: [
            // Here you are copying the old array into the new one,
            // keeping the current car at the first position 
            ...state.currentCart,
            // Here you are updating the values of the object at index 0
            // and at the same time you are adding those values at 
            // the end of the array
            state.currentCart[index].count += 1,
             (state.currentCart[index].totalPrice =
              state.currentCart[index].price * state.currentCart[index].count), 
          ],
        };

What you want to do is to build a new currentCart each time and. Also you want to use an object for currentCart, not an array. If you want to keep a list of items in the cart, I suggest you tu create a nested property on the cart called items, and make that be an array. Your code example is not showing us where are you getting the action from, but I will provide you an example assuming you just have it and that the new item to add to the cart comes in the payload.

  const currentCart = state.currentCart;
  const newItem = action.payload
  return {
      ...state,
      currentCart: {
        ...currentCart,
        count: currentCart.count + 1
        totalPrice: (newItem.price * newItem.count) + currentCart.totalPrice,
        items: [...currentCart.items, newItem] 
      },
    };

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...