Given my state looks like so:
cart: [
{ id: 1, name: 'apple', price: 100, quantity: 1 }
]
How do I setState of that specific object's quantity property ?
You can get the indexOf the item in the cart which you want to update, and update the cart with everything up to that item, your updated item, and the rest of the items.
Example
class App extends React.Component {
state = {
cart: [
{ id: 1, name: "apple", price: 100, quantity: 1 },
{ id: 2, name: "orange", price: 50, quantity: 10 },
{ id: 3, name: "banana", price: 20, quantity: 100 }
]
};
increaseQuantity = item => {
this.setState(previousState => {
const { cart } = previousState;
const itemIndex = cart.indexOf(item);
return {
cart: [
...cart.slice(0, itemIndex),
{ ...cart[itemIndex], quantity: cart[itemIndex].quantity + 1 },
...cart.slice(itemIndex + 1)
]
};
});
};
render() {
return (
<div>
{this.state.cart.map(item => (
<div key={item.id} onClick={() => this.increaseQuantity(item)}>
{item.name} {item.quantity}
</div>
))}
</div>
);
}
}
{cart} here?quantity comes in very frequently, there could be race conditions where the state is not updated properly unless the cart is taken from the previous state in the setState callback.cart from previousState rather than using it directly..bind instead of () => {} as bind is about twice as performant. Happy coding! :)You can update your cart as
updateCart(id, itemAttributes) {
var index = this.state.cart.findIndex(x=> x.id === id);
if (index === -1)
// handle error
else
this.setState({
cart: [
...this.state.cart.slice(0, index),
Object.assign({}, this.state.cart[index], itemAttributes),
...this.state.cart.slice(index+1)
]
});
}
then call your updateCart function with id of your cart item as
this.updateCart(1, {quantity: 2});
Object.assign in the other? Wouldn't it be better to do spread on all three? this.setState(prev => ({
cart: [{ ...prev.cart[0], quantity: 10, }].concat(prev.cart.slice(1))
}));
Copy the array and replace the object you wanna change with a copied version. If you do that often you may use some utilities:
const replace = index, replacer) => arr =>
arr.map((el, i) => i === index ? replacer(el) : el);
const key = (k, replacer) => state => ({...state, [k]: replacer(state[k]) });
Usable as:
this.setState(key(
"cart",
replace(
0,
key("quantity", () => 10)
)
));