3

I've been struggling with this from yesterday, and couldn't solve it.

Basically, we are making a website for a restaurant, which customer can use to order foods and pay for it. The feature I'm implementing now is, when user press the checkout button, it goes to /order_confirm and display all the menus ordered. I'm trying to pass the order number by setting the url as /order_confirm/id where id is the order number. Everything works fine, except that when I do setState() to change the value of the ordId which is state and pass the state value to the according class, it seems like setstate not changing the value at all.

handleCheckoutRequest = async () => {
const { tableNumber } = this.state;
const orderOrdered = 1;
const menuItemIds = this.props.menuItems.map((a) => a.id);
const menuItemCounts = this.props.menuItems.map((a) => a.count);

await API.post(`/orders/`, null, {
      params: { tableNumber, orderStatus: orderOrdered },
    })
      .then(async (response) => {
        const orderId = response.data.id; // this works

    await API.post(`/ordered_items/${orderId}`, null, {
      params: { menuItemIds, menuItemCounts },
    })
      .then((response) => {
        this.setState({
            responses: ["Successfully added order items"], // this works
            responseStatus: "success", // this works as well
            ordId: orderId, // this doesn't
        });
        console.log(orderId); // display 25 on the console (which is right)
        console.log(this.state.ordId); // display -1 which is the default value
      })
      .catch((error) => {
        console.log(error);
      });
  })
};

I get this error in console.

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

I've tried setting the tempo, using the arrow function in the setState(), declaring method outside and using the method to change the value. It all didn't work.


This is handleCheckout method.
handleCheckout = () => {
  const { menuItems } = this.props;
  const { tableNumber } = this.state;
  let responses = [];
  if (tableNumber === -1 || !tableNumber)
    responses.push("No table has been selected");
  if (menuItems.length < 1)
    responses.push("No menu items have been added to cart");
  if (responses.length > 0) {
    this.setState({ responses, responseStatus: "fail" });
    return;
  }
  this.setState({ responses: [], responseStatus: "" });

  this.handleCheckoutRequest();
};

this is the part where I'm passing the state as props.

<div className="cart__bottom">
   <Checkout
      id={this.state.ordId}
      onTableChange={this.handleTableChange}
      onCheckout={this.handleCheckout}
      responses={responses}
      responseStatus={responseStatus}
   />
</div>

This is render() of where it's passed

render() {
const { id, onTableChange, onCheckout, responses, responseStatus } = this.props;
return (
  <div className="cart__checkout">
    <Response responses={responses} responseStatus={responseStatus} />
    <input
      className="input mb-2"
      type="number"
      name="tableNumber"
      placeholder="Table Number"
      onChange={onTableChange}
    />
    <Link to={{
      pathname: "/order_confirm/" + id
    }}>
      <button
        className="button is-primary is-fullwidth"
        onClick={onCheckout}
      >
        Checkout
      </button>
    </Link>
  </div>
);

}

I also found an article that seems like it could be a solution to my problem. Only barrier is that I'm not good enough with React to apply the solutions.
Avoid React state update warnings on unmounted components

brady
  • 43
  • 5
  • 3
    Does this answer your question? [setState doesn't update the state immediately](https://stackoverflow.com/questions/41278385/setstate-doesnt-update-the-state-immediately) – Sysix Feb 22 '21 at 19:47
  • A tip is to try to avoid nesting promises. You are also using async await and then you are not using it. Try to stick to one of them. – Cyrus Zei Feb 22 '21 at 19:48
  • Try to separate the api request logic from the UI logic. I think a "repository pattern" could solve your problem. – Pablo Darde Feb 22 '21 at 19:53
  • @Sysix Tried top 3 answers, it doesn't solve the problem. – brady Feb 22 '21 at 21:25
  • where do you use the state? maybe u need `useEffect` – Sysix Feb 22 '21 at 22:03
  • I'm using state because the only way I can get the order number is when API.post is returning, I need to pass the order number to a component as props but I don't have access to the response.data.id outside this post function... – brady Feb 22 '21 at 22:27
  • Please share the rest of the related code of your app, such as the react component where you are executing that call, and the hooks/lifecycle methods, the error you are getting seems to be related to that part – tmilar Feb 23 '21 at 00:09
  • I've updated the question. Please have a look, thanks. – brady Feb 23 '21 at 11:12
  • When an API call is made, is it in onCheckout/handleCheckout method? – G07cha Feb 23 '21 at 12:17
  • @G07cha I've updated so that it shows which method it is in. It's in handleCheckoutRequest(). – brady Feb 23 '21 at 16:06
  • This doesn't quite give insight into the chain of execution, is it being called when the Checkout button is pressed? Because the button has a onClick handler with a different name. – G07cha Feb 24 '21 at 08:25
  • Added handleCheckout method! Should've added it the first time – brady Feb 24 '21 at 12:19

1 Answers1

0

Try not to mix async await with normal promise. Stick to one of them. Also try not to nest promises since that will give you callback hell.

const postOrder = async () => {
  const apiPostOrdersResponse = await API.post(`/orders/`, null, {
    params: { tableNumber, orderStatus: orderOrdered },
  });

  const orderId = apiPostResponse.data.id;

  const apiPostOrderItemResponse = await API.post(
    `/ordered_items/${orderId}`,
    null,
    {
      params: { menuItemIds, menuItemCounts },
    }
  );

  this.setState({
    responses: ['Successfully added order items'],
    responseStatus: 'success',
    ordId: orderId,
  });
};
Cyrus Zei
  • 2,589
  • 1
  • 27
  • 37