About useState being async

Hi there.

I am bulding a cart using state and provider. At the beginning I had something like this:

 const addToCart = () => {
    dispatch({
      type: "ADD_TO_CART",
      item: {
        key: key,
        id: id,
        title: title,
        description: description,
        img: img,
        price: price,
      },
    });
  };
<Button
                          variant="default"
                          className="btnBgColor btnTextColor"
                          onClick={() => {
                            setKey(figure.key);
                            setId(figure.id);
                            setTitle(figure.title);
                            setDescription(figure.description);
                            setImg(figure.img);
                            setPrice(figure.price);
                            addToCart();
                          }}
                        >

It didn´t work properly. I was one step behind all the time: when adding the first item, empty object in basket array, when adding second item, first item in basket array, and so on.

I changed my approach and did something like this:

const addToCart = (key, id, title, description, img, price) => {
    setKey(key);
    setId(id);
    setTitle(title);
    setDescription(description);
    setImg(img);
    setPrice(price);
    dispatch({
      type: "ADD_TO_CART",
      item: {
        key: key,
        id: id,
        title: title,
        description: description,
        img: img,
        price: price,
      },
    });
  };
<Button
                          variant="default"
                          className="btnBgColor btnTextColor"
                          onClick={() => {
                            addToCart(
                              figure.key,
                              figure.id,
                              figure.title,
                              figure.description,
                              figure.img,
                              figure.price
                            );
                          }}
                        >

Now it works. And I don´t understand why. By passing parameters in my function, is updating the state inmediately? Without using async-await?
By the way, I tried to make it async but as soon as I wrote “await” my code editor was saying that it wouldn´t have effect.

Thanks.

Hello there,

Do you have the code publicly available somewhere we can see?

Specifically, it is hard to tell where addToCart is defined? That is, how does it get access to key, id, title etc. ?


If these are useState callbacks, then the setState event is not guaranteed to happen during the current lifecycle of the component. In this way, it is asynchronous.

That is, it is React’s internal lifecycle hooks which are asynchronous - not the component itself.

In general, the hooks do not return promises for you to await, but there are many methods to correctly work with the hooks to not encounter unexpected behaviour.

Github was driving me crazy but now I´m able to share my repo:

Thank you, for sharing that.

Yeah, they struggled for a while today.


I think this is all fine, now. You were correct in your summation as to why your refactor worked.

The only comment I would make is:
You can turn this:

item: {
        key: key,
        id: id,
        title: title,
        description: description,
        img: img,
        price: price,
      },

into this:

item: {
        key,
        id,
        title,
        description,
        img,
        price,
      },

And, I would refactor the addToCart function to take in an object literal, because it can get confusing when you have functions taking in so many parameters - you could accidentally mix up the order of inputs:

const addToCart = (key, id, title, description, img, price) => {
const addToCart = ({key, id, title, description, img, price}) => {

One last thing:
It is entirely up to how you decide you want your app to function, but it is not uncommon to have this workflow:

  1. Dispatch item to server
  2. Server responds back “OK”
  3. Update local state with what server knows as “truth”

Currently, you are doing this:

  1. Update local state
  2. Dispatch item to server

This has the problem of what if the server does not get the updated state?

In your current case, you do not have this external server, but the same logic could still apply - you have two copies of the app state (one in the OnePiece component, and the other in the store) - they could become disjoint.

Hope this helps

Thanks for your tips. Eventually I will use an external server, so I’ll have this in my mind :slight_smile: