Problem checking if an item exists in cart - reactjs

hello I've been having a problem with checking if an item already exists in the cart. if so I want only the quantity to be updated for some reason it keeps adding the item as a new item even if it exists. This is what I've been doing:
// Adding Items to cart
const onAdd = (product, quantity) => {
const checkProductInCart = cartItemsFromLocalStorage.find((item) => item.id === product.id);
setTotalPrice((prevTotalPrice) => (prevTotalPrice + Math.round((product.price * quantity)*100)/100));
setTotalQuantities((prevTotalQuantities) => prevTotalQuantities + quantity);
if(checkProductInCart) {
// eslint-disable-next-line
const updatedCartItems = cartItemsFromLocalStorage.map((cartProduct) => {
if(cartProduct.id === product.id) return {
...cartProduct,
quantity: cartProduct.quantity + quantity
}
})
setCartItems(updatedCartItems);
} else {
product.quantity = quantity;
setCartItems([{ ...product }, ...cartItems]);
}
toast.success(` ${product.name} added to the cart.`);
}

Seems like the issue is on your cartItemsFromLocalStorage.map implementation. The map function should return the product even if it isn't the one you're looking to update. Try updating that map to
cartItemsFromLocalStorage.map((productOnCart) => {
if (productOnCart.id === product.id) {
return { ...productOnCart, cartProduct.quantity + quantity }
}
return productOnCart
})
If you don't return anything your list will be full of undefined objects

Related

How to use "if" inside useState prevState map

Does anybody know how can i use if statement like this.
This example doesnt work
uppy.on('complete', (result) => {
result.successful.forEach((file) =>
setImgs((prevState) =>
prevState.map((item) => {
if(item.id === file.id) {
return {
...item,
image: file.preview
}
}
})
)
)
})
And this works, but there s no if
uppy.on('complete', (result) => {
result.successful.forEach((file) =>
setImgs((prevState) =>
prevState.map((item) => ({
...item,
image: file.preview,
}))
)
)
})
I don't think you need to map if you're just trying to find an item.
You could do
const item = prevState.find(x.id ==> file.id)
return item? {...item.image:file.preview} : null
"doesn't work" will need more specification. Out of observation I can tell that it needed to have else statement or without, in order to return item if no change is required. The variable - item is unchanged element of imgs array, which we put back.
This is after refactoring your pseudocode:
uppy.on("complete", (result) => {
result.successful.forEach((file) =>
setImgs((prevState) =>
prevState.map((item) => {
if (item.id === file.id) {
return { id: item.id, image: file.preview };
} else return item;
})
)
);
});
Check the sandbox here
Since you are using a map that returns a new array, also you are trying to add an image key to the matched item only then, you need to also return for the else case.
const data = state.map((item) => {
if (item.id === file.id) return { ...item, image: file.preview };
return item;
});

cant add existing product in cart in reducer in redux with react native

am working on a react native application that has a maternal shop,am using redux to work on the global state,and in my reducers i have to handle adding to cart,if product has not been existing in the cart or if product exists in the cart, my aim is just to increase its quantity without increasing the total product count
here are my actions and reducers
export const ADD_TO_CART = 'ADD_TO_CART';
export const ADD_QUANTITY = 'ADD_QUANTITY';
export const SUB_QUANTITY = 'SUB_QUANTITY';
export const DELETE_ITEM = 'DELETE_ITEM';
export const addToCart = (payload) => {
type: ADD_TO_CART,
payload
}
export const addQuantity = (payload) => {
type: ADD_QUANTITY,
payload
}
export const subQuantity = (payload) => {
type: SUB_QUANTITY,
payload
}
export const deleteItem = (payload) => {
type: DELETE_ITEM,
payload
}
my reducers for the cart
import { ADD_TO_CART,DELETE_ITEM,SUB_QUANTITY,ADD_QUANTITY} from '../actions/cartItems';
const initialState = {
itemsCount : 0,
cartItems:[],
cartTotalAmount:0,
}
const cartReducer = (state=initialState, action)=>{
switch(action.type){
case ADD_TO_CART:
let cart = {
id:action.payload.itemId,
quantity:action.payload.quantity,
name:action.payload.itemTitle,
image:action.payload.itemImg,
price:action.payload.itemPrice,
cartAmount:action.payload.quantity * action.payload.itemPrice
}
if(state.itemsCount === 0){
state.cartItems.push(cart);//just push the cart
return {
...state,
itemsCount:state.itemsCount+1,
cartTotalAmount:state.cartItems.map(item => {
state.cartTotalAmount+item.cartAmount
})
}
}else{
let exists =false;
let i =0;
while(i<state.cartItems.length){
if(state.cartItems[i].id === action.payload.itemId){
state.cartItems[i].quantity++;
exists = true;
}
return{
...state,
itemsCount:state.itemsCount
}
i++;
}
state.cartItems.map((key,item) => {
if(item.id === action.payload.itemId){
// {...item,quantity:item.quantity+1}
state.cartItems[key].quantity++;
exists = true
}
return {
...state,
itemsCount:state.itemsCount,
}
})
if(!exists){
let _cart = {
id:action.payload.itemId,
quantity:action.payload.quantity,
name:action.payload.itemTitle,
image:action.payload.itemImg,
price:action.payload.itemPrice,
cartAmount:action.payload.quantity * action.payload.itemPrice
}
state.cartItems.push(_cart)
return {
...state,
itemsCount:state.itemsCount+1,
cartTotalAmount:state.cartItems.map(item => {
state.cartTotalAmount+item.cartAmount
})
}
}
}
case ADD_QUANTITY:
return {
...state,
cartItems:state.cartItems.map(
item => item.id === action.payload.itemId
? {...item, quantity: item.quantity+1 }
: item
),
}
case DELETE_ITEM:
let newCartItems = state.cartItems.filter(
(item) => {return item.id != action.payload.itemId}
)
let count = state.itemsCount-1;
return {
...state,
itemsCount:count,
cartItems:newCartItems,
}
case SUB_QUANTITY:
return {
...state,
cartItems:state.cartItems.map(
item => item.id === action.payload.itemId
? {...item, quantity: item.quantity-1 }
: item
),
}
// case ADD_TO_WISH_LIST:
// for(let i=0; i < state.wishListItems.length; i++){
// if(state.wishListItems[i].id === action.item.id){
// return {
// ...state,
// wishListItems: state.wishListItems.map(item => item.id === action.item.id ?
// { ...item, quantity: item.quantity+1 } :item
// ) ,
// }
// }
// else{
// let updatedWishListItems = [...state.wishListItems, action.item];
// let count = state.wishCount + 1;
// }
// }
// return{
// ...state,
// wishCount : count,
// wishListItems :updatedWishListItems
// }
// case DELETE_FROM_WISH_LIST:
// let newWishListItems = state.wishListItems.filter(
// (item)=>{
// return item.id!=action.item.id
// }
// );
// return {
// ...state,
// wishListItems : newWishListItems ,
// }
default:
return state
}
}
export default cartReducer;
the first case in the reducer for adding to cart when itemsCount === 0 works however when the cart has more than one item the reducer has failed to execute properly and am stuck help needed
Issues
Don't store the itemsCount and cartTotalAmount values in state, these are easily derived from state data. Storing duplicate or derived data is anti-pattern.
const initialState = {
itemsCount : 0, // <-- easily computed from cart items
cartItems:[],
cartTotalAmount:0, // <-- easily computed from cart items
}
Don't mutate your state by pushing directly into your cartItems array.
state.cartItems.push(cart); // <-- mutates state reference
You need to search the cartItems first to see if you've already added a cart item.
Solution
case ADD_TO_CART:
const {
itemId,
itemImg,
itemPrice,
itemTitle,
quantity,
} = action.payload;
// search if item is already in cart by item id
const inCart = state.cartItems.some(item => item.id === itemId);
if (inCart) {
// already in cart, shallow copy cart items
return {
...state,
cartItems: state.cartItems.map(item => item.id === itemId ? {
// found item, shallow copy item and update quantity property
...item,
quantity: item.quantity + 1,
} : item),
}
} else {
return {
...state,
cartItems: [
// shallow copy cart items
...state.cartItems,
// add new cart item
{
id: itemId,
quantity: quantity,
name: itemTitle,
image: itemImg,
price: itemPrice,
}
],
}
}
...
You can apply similar updating patterns for other action types that update the cart items.
To compute the itemsCount in your UI
const itemsCount = cartItems.reduce((count, { quantity }) => count + quantity, 0)
To compute the cartTotalAmount
const cartTotalAmount = cartItems.reduce(
(totalAmount, { price, quantity }) => totalAmount + quantity * price,
0,
);
These can be combined into a single calculation in a single pass
const { cartTotalAmount, itemsCount } = cartItems.reduce(
({ cartTotalAmount, itemsCount }, { price, quantity }) => ({
cartTotalAmount: cartTotalAmount + quantity * price,
itemsCount: itemsCount + quantity,
}),
{
cartTotalAmount: 0,
itemsCount: 0,
},
);

React - event.target.id no getting id from element

I'm trying to get the id from the element and then update it's state to the new id value.
The function where I handle the update:
updateID = (e) => {
console.log("IDFEEDING::" + this.state.id.feeding);
const { id, name } = e.target;
console.log("HereID::" + id + "," + name);
this.setState((prevState) => {
const updatedID = {
...prevState.id,
[name]: id
};
return {
id: updatedID
}
})
}
and here the element where I call the function to update the values. Update values works, but id no.. doesn't gives me erros, it's just doesn't update, I can't get the new id when I select a new radio button.
<RadioGroup id={this.state.id.feeding} aria-label="quiz" name="feeding" value={this.state.group.feeding}
onChange={(event) => {
var group = { ...this.state.group };
group.feeding = event.target.value;
this.setState({ group });
this.updateTotal(event)
var id = { ...this.state.id };
id.feeding = event.target.id;
this.setState({ id });
this.updateID(event)
}}>
Thanks in advance :)
setState is async, so it won't update the value immediately. You would need to make use of callback approach.
Also since you are executing many things within the onClick handler, I recommend you take it out into new function
updateID = ({ id, name }) => {
console.log("IDFEEDING::" + this.state.id.feeding);
console.log("HereID::" + id + "," + name);
this.setState((prevState) => {
const updatedID = {
...prevState.id,
[name]: id
};
return {
id: updatedID
}
})
}
onChange= (event) => {
var group = { ...this.state.group };
const {id, value, name } = event.target;
group.feeding = value;
var id = { ...this.state.id };
id.feeding = id;
// Use one setState instance to update both
this.setState({ id, group }, () => {
// using on callback
this.updateTotal(group);
this.updateID({id, name})
});
}
}
...
<RadioGroup id={this.state.id.feeding} aria-label="quiz" name="feeding" value={this.state.group.feeding}
onChange={this.onChange}>

React native push with multiple key and value

I have a group of checkboxes, whenever I select a checkbox I need to push an array of data, like { 'index':1, 'photo':'sample.png' } to state, and whenever I unselecting the checkbox, I need to remove it from the state. after I need to loop through the state to get index and photo to be used
handleSelection = async (media, index, isSelected) => {
alert(index);
if (isSelected == true) {
this.state.mediaSelected.push(media.photo);
} else {
this.state.mediaSelected.splice(this.state.mediaSelected.indexOf(media.photo), 1);
}
console.warn(this.state.mediaSelected);
}
this is working for single value without the key, is there any way to push it with key and value?
You should always update state with this.setState in your case would be something like this:
handleSelection = async (media, index, isSelected) => {
alert(index);
if (isSelected == true) {
this.setState({
mediaSelected: this.state.mediaSelected.push({
index,
photo: media.photo
})
});
} else {
this.setState({
mediaSelected: this.state.mediaSelected.splice(this.state.mediaSelected.indexOf(media.photo), 1)
});
}
console.warn(this.state.mediaSelected);
}
Try this:
Sorry I am working as well as answering your question so it is taking time.
handleSelection = async (media, index, isSelected) => {
let selectPhotosObj = this.state.selectPhotosObj || [];
if (isSelected == true) {
const data = { index, photo: media.photo };
//this.state.selectedPhotoObj will be the container for your object.
selectPhotosObj.push(data)
//need to set the new Array of Object to the state.
this.setState({ mediaSelected: media.photo, selectPhotosObj });
} else {
const removedPhoto = this.state.mediaSelected.filter(value => value !== media.photo);
selectPhotosObj = this.state.selectedPhotosObj.filter(value => value.index !== index);
this.setState({
mediaSelected: removedPhoto,
selectPhotosObj
})
}
console.warn(selectPhotosObj);
}

How to solve Error Use object destructuring prefer-destructuring - React

I am stuck with an ugly issue which I am unable to resolve. I am beginner in React.
This is my Code
handleCheckChildElement(event) {
let items = this.state.items;
items.forEach(items = () => {
if(items.value === event.target.value) {
items.isChecked = event.target.checked;
}
});
this.setState({ items });
}
This is the image of the error -
Use below code for line #55 :
let {items}= {...this.state};
Read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring
Your code can be improved to something like below. Please find relevant comments in the code below for your better understanding
handleCheckChildElement(event) {
const { items } = this.state; //extract state values like this to a const variable
const newItems = items.map(item => { //do map on items because map returns a new array. It’s good practice to use .map than forEach in your case
if(item.value === event.target.value) {
item.isChecked = event.target.checked;
return item; //return updated item object so that it will be pushed to the newItems array
}
return item; // return item because you need this item object as well
});
this.setState({ items: newItems}); //finally set newItems array into items
}
handleCheckChildElement(event) {
const items = this.state.items;
const filtered = items.filter(item => item.value === event.target.value)
.map(item => item.isChecked = event.target.checked) ;
this.setState({items : [...filtered] );
}

Resources