skip to Main Content

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


  1. Chosen as BEST ANSWER

    Updating the updateCart function with this helps solving the problem

      updateCart = (newItem) => {
        if (
          this.state.cart.filter(
            (element) => element.dish === newItem.dish && element.dish !== ""
          ).length > 0
        ) {
          // console.log("inside if");
          const indx = this.state.cart.findIndex(
            (element) => element.dish === newItem.dish
          );
          this.setState(() => {
            this.state.cart[indx].qnty = newItem.qnty;
            // this.state.cart.slice(2);
          });
        } else {
          // console.log("inside else");
          this.setState({
            cart: [...this.state.cart, newItem],
          });
        }
        // console.log(this.state.cart.slice(2));
      };
    

  2. This isn’t updating state:

    this.state.cart[indx].qnty = newItem.qnty;
    

    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:

    this.setState({
      cart: [newItem, ...this.state.cart],
    });
    

    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:

    - search for a matching existing item
    - if one is found
      - create a new shallow copy of that item, updating data as needed
      - set state to a new array containing the copy of the item and all existing items *except* the matching one
    - else
      - set state to a new array containing a new item and all existing items
    

    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:

    updateCart = (newItem) => {
      if (this.state.cart.find(c => c.dish === newItem.dish && c.dish !== "")) {
        this.setState({
          cart: [...this.state.cart.map(c => {
            if (c.dish === newItem.dish && c.dish !== "") {
              return { ...c, qnty: newItem.qnty }
            } else {
              return c;
            }
          })],
        });
      } else {
        this.setState({
          cart: [newItem, ...this.state.cart],
        });
      }
    };
    

    The main difference (other than shortening your if condition from filter to find 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search