hi . I am planning to create a shopping cart system for my site. I use React and Redux toolkit. But when I want to dispatch my states, I encounter this error. Thank you for helping me. cartSlide (Cart Reducer) :
import {createSlice} from "@reduxjs/toolkit";
const initialState = {
selectedItems: [],
itemsCounter: 0,
total: 0,
checkout: false
}
const sumItems = items => {
const itemsCounter = items.reduce((total , product) => total product.quantity, 0)
const totalPrice = items.reduce((total , product) => total product.price * product.quantity,0).toFixed(2)
return {
itemsCounter,
totalPrice
}
}
export const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
AddItem:(state,action)=>{
if (!state.selectedItems.find(item => item.id === action.payload.id)) {
state.selectedItems.push({
...action.payload,
quantity: 1
})
}
return {
...state,
selectedItems: [...state.selectedItems],
...sumItems(state.selectedItems),
checkout: false
}
},
RemoveItem: (state, action) => {
const newSelectedItems = state.selectedItems.filter(item => item.id !== action.payload.id);
return {
...state,
selectedItems: [...newSelectedItems],
...sumItems(newSelectedItems)
}
},
Increase: (state, action) => {
const indexI = state.selectedItems.findIndex(item => item.id === action.payload.id);
state.selectedItems[indexI].quantity ;
return {
...state,
...sumItems(state.selectedItems)
}
},
Decrease: (state, action) => {
const indexD = state.selectedItems.findIndex(item => item.id === action.payload.id);
state.selectedItems[indexD].quantity--;
return {
...state,
...sumItems(state.selectedItems)
}
},
Checkout: () => {
return {
selectedItems: [],
itemsCounter: 0,
total: 0,
checkout: true
}
},
Clear: () => {
return {
selectedItems: [],
itemsCounter: 0,
total: 0,
checkout: false
}
}
}
})
export const {AddItem,RemoveItem,Increase,Decrease,Checkout,Clear} = cartSlice.actions
export default cartSlice.reducer
The error is for the AddItem action, and when I delete the return part, the code works. this part:
AddItem:(state,action)=>{
if (!state.selectedItems.find(item => item.id === action.payload.id)) {
state.selectedItems.push({
...action.payload,
quantity: 1
})
}
return {
...state,
selectedItems: [...state.selectedItems],
...sumItems(state.selectedItems),
checkout: false
}
},
CodePudding user response:
Don't both modify the state object state.selectedItems.push
and use a return
.
Option A - Modify Draft
AddItem: (state,action) => {
// Check if item exists
if (!state.selectedItems.find(item => item.id === action.payload.id)) {
// add item since it did not exist.
state.selectedItems.push({
...action.payload,
quantity: 1
})
}
// Calculate new count and totals.
const sum = sumItems(state.selectedItems);
// Apply new count and totals to the state.
state.itemsCounter = sum.itemsCounter;
state.totalPrice = sum.totalPrice;
// Set checkout to false.
state.checkout = false;
}
Option B - New State
AddItem: (state,action) => {
// create a new array containing selected items.
let newItems = [
...state.selectedItems;
];
// check if item already exists
if (!newItems.find(item => item.id === action.payload.id)) {
// add item since it did not exist
newState.selectedItems.push({
...action.payload,
quantity: 1
});
}
// return a new state
return {
...state,
selectedItems: newItems,
...sumItems(newItems),
checkout: false
}
}
You should probably stick with modifying the draft method unless you intend to replace the state with a completely new state. Using the draft method Immer should handle the reference updates where needed and allows you to write code as if you were editting a normal mutable object (for the most part, see the docs for some limitations).