I'm using React context to add products to the cart with simple logic, and I'm using useReducer
hook for adding items to the cart.
With Redux Toolkit the logic is easy to implement, firstly please check my redux logic:
const cartItemSlice = createSlice({
name: "cart",
initialState: {
items: [],
totalQuantity: 0,
totalAmount: 0,
},
reducers: {
addProduct(state, action) {
const newCartItems = action.payload; //items from dispatch object
const existingItem = state.items.find((el) => el.id === newCartItems.id);
state.totalQuantity ;
if (!existingItem) {
state.items.push({
id: newCartItems.id,
quantity: 1,
title: newCartItems.title,
price: newCartItems.price,
image: newCartItems.image,
totalPrice: newCartItems.price,
});
} else {
existingItem.quantity ;
}
},
}
})
Now HOW CAN I DO THAT SAME THING WITH REACT CONTEXT? How to get the array that is matched with the id and add the item to the cart while dispatching it, here I'm trying to put that in context:
import React, { useReducer } from "react";
const CartItemContext = React.createContext();
const CartContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(
(state, action) => {
if (action.type === "ADD-ITEM") {
return {
...state,
items: state.items.find((el) => el.id === action.payload.id),
totalQuantity: state.totalQuantity ,
};
}
},
{
items: [],
totalPrice: 0,
totalQuantity: 0,
}
);
return (
<CartItemContext.Provider
value={{
items: state.items,
totalPrice: state.totalPrice,
totalQuantity: state.totalQuantity,
dispatch,
}}
>
{children}
</CartItemContext.Provider>
);
};
export { CartItemContext, CartContextProvider };
And here when I click the add to cart button
in my component:
export default function BookItems(props) {
const { id, title, price, image } = props;
const cartItemsCtx = useContext(CartItemContext);
const { dispatch } = cartItemsCtx;
const addToCartHandler = () => {
dispatch({
type: "ADD-ITEM",
payload: {
id, title, price, image
},
});
};
return (
<div className={classes.product__item}>
<Link href={`/products/${id}`}>
<Image src={image} alt={title} className={classes.image} fill />
<h3>{title}</h3>
</Link>
<div className={classes.bottom}>
<p>${price}</p>
<button onClick={addToCartHandler}>Add to cart</button>
</div>
</div>
);
}
CodePudding user response:
You can do it as below, with the help of the Spread syntax. If there is an existing one, change its quantity and add it to state.items
; otherwise, add the new one.
import React, { useReducer, createContext } from "react";
// I moved it out here for readability
const reducer = (state, action) => {
if (action.type === "ADD-ITEM") {
const newCartItems = action.payload;
let existingItem = state.items.find((el) => el.id === newCartItems.id);
if (existingItem) {
existingItem = { ...existingItem, quantity: existingItem.quantity 1 };
}
return {
...state,
items: !existingItem ? [...state.items, newCartItems] : [...state.items, existingItem],
totalQuantity: state.totalQuantity ,
};
}
};
// I moved it out here for readability
initialState = {
items: [],
totalPrice: 0,
totalQuantity: 0,
};
const CartItemContext = createContext();
const CartContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<CartItemContext.Provider
value={{
items: state.items,
totalPrice: state.totalPrice,
totalQuantity: state.totalQuantity,
dispatch,
}}
>
{children}
</CartItemContext.Provider>
);
};
export { CartItemContext, CartContextProvider };