So basically I am making a shopping cart and I want to add a functionality if an item is already in the cart then increase it's quantity by 1. If you add same item and they have different sizes then show them separetely. I managed to deal with increasing the quantity in my reducer's logic but when I add another block condition it doesn't work. Here is the code:
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
bagData: [],
};
export const bagDataSlice = createSlice({
name: "bagDataProducts",
initialState,
reducers: {
sendDataToCardComponent: (state, action) => {
let { id, size } = action.payload;
const findItemById = state.bagData.find(
(item) => item.id === id && item.size === size
);
if (findItemById) {
state.bagData.filter((item, i) => (state.bagData[i].quantity = 1));
} else {
state.bagData.push({ ...action.payload, quantity: 1 });
}
},
increaseItemQuantity: (state, { payload }) => {
state.bagData.filter((item, i) =>
item.id === payload ? (state.bagData[i].quantity = 1) : item
);
},
decreaseItemQuantity: (state, { payload }) => {
state.bagData.filter((item, i) =>
item.id === payload && item.quantity > 1
? (state.bagData[i].quantity -= 1)
: item
);
},
removeItem: (state, { payload }) => {
state.bagData = state.bagData.filter((item) => item.id !== payload);
},
},
});
when I add the condition of
const findItemById = state.bagData.find(
(item) => item.id === id && item.size === size
);
it only increments the item without checking it's size, only checks it's id even though there are 2 conditions for that function. Could you please explain that to me?
CodePudding user response:
state.bagData.filter((item, i) => (state.bagData[i].quantity = 1));
For your first case, this is updating every item's quantity if you found a matching item by id
and size
. Since you've already found the item and stored it in findItemById
, you should be able to use the following.
Caveat, Immer only supports mutating array elements by index so use findIndex()
instead of find()
.
const itemIndex = state.bagData.findIndex(
(item) => item.id === id && item.size === size
);
if (itemIndex !== -1) {
state.bagData[itemIndex].quantity ;
} else {
state.bagData.push({ ...action.payload, quantity: 1 });
}
Here's a quick demo showing that this works
const initialState = {
bagData: [{
id: 1,
quantity: 1,
size: "S"
}]
};
const sendDataToCardComponent = (action) =>
immer.produce(initialState, (state) => {
let { id, size } = action.payload;
const itemIndex = state.bagData.findIndex(
(item) => item.id === id && item.size === size
);
if (itemIndex !== -1) {
state.bagData[itemIndex].quantity ;
} else {
state.bagData.push({ ...action.payload, quantity: 1 });
}
});
console.log(
"increment existing",
sendDataToCardComponent({ payload: { id: 1, size: "S" } })
);
console.log(
"add new",
sendDataToCardComponent({ payload: { id: 1, size: "M" } })
);
.as-console-wrapper { max-height: 100% !important; }
<script src="https://cdn.jsdelivr.net/npm/immer"></script>
As mentioned in the comments, you're misusing Array.prototype.filter() which should only be used to return a new array with items filtered in or out based on a predicate. Your code can be cleaned up somewhat
increaseItemQuantity: (state, { payload }) => {
const found = state.bagData.findIndex(({ id }) => id === payload);
if (found !== -1) {
state.bagData[found].quantity ;
}
},
decreaseItemQuantity: (state, { payload }) => {
const found = state.bagData.findIndex(({ id }) => id === payload);
if (found !== -1) {
state.bagData[found].quantity--;
}
},
Your last reducer is using filter()
correctly but Immer also supports splice()
removeItem: (state, { payload }) => {
const found = state.bagData.findIndex(({ id }) => id === payload);
if (found !== -1) {
state.bagData.splice(found, 1);
}
},