I have a useState object something like
const [data, setData] = useState({
dish: "",
category: "",
cost: 0,
qnty: 0,
img: "",
})
Here qnty
is a counter variable. Everytime the counter is updated, data
obj too is updated. Every time data
is updated, updateCart
function is called and the values in the context state are updated.
Here is the context state
state = {
updateCart: this.updateCart,
cart: [
{
dish: "",
category: "",
cost: 0,
qnty: 0,
img: "",
}
]
updateCart
function
updateCart = (newItem) => {
this.setState({
cart: [newItem, ...this.state.cart],
});
};
The function is working perfectly fine. A new array is being added, that’s good. But, since the qnty
is a counter, I want to update the cart
array in the context state every time updateCart
is called, instead of adding a new row for the updated qnty
.
Just for example, if the cart
already has an element (object) with qnty
as 1, and if I change the qnty
to 2, a new element is added into the cart
array. Instead, I want to update the existing 1 to 2.
How do I do that?
This is what i’ve tried at updateCart
function
updateCart = (newItem) => {
if (
this.state.cart.filter(
(element) => element.dish === newItem.dish && element.dish !== ""
).length > 0
) {
const indx = this.state.cart.findIndex(
(element) => element.dish === newItem.dish
);
this.state.cart[indx].qnty = newItem.qnty;
} else {
this.setState({
cart: [newItem, ...this.state.cart],
});
}
};
2
Answers
Updating the
updateCart
function with this helps solving the problemThis isn’t updating state:
This is mutating state, which is bad for a variety of reasons. Note how you call
this.setState()
to update state in your working version:Whether you’re updating an existing array element or adding a new one, the operation to update state doesn’t change. All that changes is how you construct the new array to send to state.
In general the logic for updating an existing item vs. adding a new one would be something like:
In both cases it’s critical to note that state is being set to a new array, not just modifying the existing one.
An example of this logic could be something like:
The main difference (other than shortening your
if
condition fromfilter
tofind
and a shorter variable name to reduce clutter) is the use of.map()
when setting state for cases where the element exists.Overall
.map()
returns a new array, so it’s safe for setting state in this manner. And it preserves the current order of the array. The callback to.map()
here simply checks if the current element matches the condition and, if so, returns a new element with the same values plus the one updated value. For all other elements it returns the element as-is.