this.setState and following function are not even running

It’s not logging the item of "this.state.UsersAvatars[1]", nor the "check". it’s also not changing the array, the only item in UsersAvatars is the first object

Can I please ask for your help? (:

  newUserTypeAvatarsArray = async () => {
    const avatars = this.state.avatars.map((avatar, index) => ({
      avatar: avatar,
      isChcecked: false,
      index: index,
    }));
    console.log(avatars);
    let singleUser = {
      userType: "everyone",
      isChecked: false,
      avatars: avatars,
    };
    await this.setState(
      {
        UsersAvatars: [singleUser],
      },
      () => {
        console.log(this.state.UsersAvatars[0]);
      }
    );

    await this.state.users_types.map(async (userTypee, index) => {
      console.log("in loop users_types");
      const temporaryObject = {
        userType: userTypee,
        isChecked: false,
        avatars: avatars,
      };
      let temporaryArray = await [...this.state.UsersAvatars, temporaryObject];
      await this.setState(
        (prevState) => (
          {
            UsersAvatars: temporaryArray,
          },
          function () {
            console.log("check");
            console.log(this.state.UsersAvatars[1]);
          }
        )
      );
    });
    await this.setState({
      UsersAvatarsLoading: false,
    });
  };

7 thoughts on “this.setState and following function are not even running”

  1. You cannot use the async/await pattern on this.setState. Even if it is asynchrone, it does not return a promise or something that you can await. It triggers a rerender of your component so I suspect the code following your first setState isn’t even read.

    You seem to know about the callback function of the setState, so use it to do your second setState. Think about splitting your code in two functions for a better understanding 😉

    Here are some explanation about awaiting setState

    And here is a question asking if we can call setState in the setState callback that you could find interesting.

    Reply
  2. newUserTypeAvatarsArray = () => {
        const avatars = this.state.avatars.map((avatar, index) => ({
          avatar: avatar,
          isChcecked: false,
          index: index,
        }));
        let singleUser = {
          userType: "everyone",
          isChecked: false,
          avatars: avatars,
        };
        var temporaryUsersAvatarsArray = [singleUser];
        this.state.users_types.map((userTypee, index) => {
          console.log("in loop users_types");
          temporaryUsersAvatarsArray = [
            ...temporaryUsersAvatarsArray,
            {
              userType: userTypee,
              isChecked: false,
              avatars: singleUser.avatars,
            },
          ];
        });
        this.setState({
          UsersAvatars: temporaryUsersAvatarsArray,
          UsersAvatarsLoading: false,
        });
      };
    

    This code works 🙂

    Reply
  3. You are awaiting a lot of things, but I don’t see a single one that makes sense/where await works as you may think.

    For you to be able to await something it has to return a Promise. async functions always return Promises.
    If you await something that is not a Promise or has a then()-method this await is pointless. await does especially not care about functions that use callbacks!

    1. await this.setState(...)

    await this.setState(...) is equivalent to calling this.setState(...) and await undefined;.

    Let’s fix this quickly and make setState awaitable.

    class Foo extends React.Component {
      setState = (arg, callback=null) => new Promise(
        resolve => super.setState(arg, resolve)
      ).then(callback)
    }
    

    For compatibility reasons I left the optional callback argument in there, but avoid to use it.

    2. await this.state.users_types.map(async (userTypee, index) => { ...

    Since you do array.map(async ...) you will get an array of promises. But sadly and array of promises is still just an array and not a Promise itself, and therefore you can’t await it. Promise.all() to the rescue.

    await Promise.all(this.state.users_types.map(async (userTypee, index) => { ... })

    3. let temporaryArray = await [...this.state.UsersAvatars, temporaryObject];

    this is basically an [].concat(this.state.UsersAvatars, [temporaryObject]). I don’t know why you think you need to await that. While Point 2 was at least an array of promises, this is merely an array, without any promises anywhere nereby; or anything asynchronous for that matter. Just get rid of await here.

    4. The comma operator

    (a, b) first executes the expression a and then executes and "returns" expression b.

    So var b = (console.log("a is", a), 2*a); will first log, and 2*a will be assigned to var b.

    How is that related to your code? here:

    this.setState(
      (prevState) => (
        {
          UsersAvatars: temporaryArray,
        },
        function () {
          console.log("check");
          console.log(this.state.UsersAvatars[1]);
        }
      )
    );
    

    let me rewrite this:

    this.setState((prevState) => {
        return (
          {
            UsersAvatars: temporaryArray,
          },
          function () {
            console.log("check");
            console.log(this.state.UsersAvatars[1]);
          }
        )
    });
    

    or

    this.setState((prevState) => {
      // create an object and ignore it
      ({
        UsersAvatars: temporaryArray,
      });
      // and return the function as "object with changes to the state"
      return function () {
        console.log("check");
        console.log(this.state.UsersAvatars[1]);
      }
    });
    

    I guess you meant to write

    this.setState({
        UsersAvatars: temporaryArray
      },
      () => {
        console.log("check");
        console.log(this.state.UsersAvatars[1]);
      }
    );
    

    So much to the obvious errors.

    I have a feeling that besides these errors, something is off about what the function does. The fact that avatars is an array, and users_types is an array and every item in users_types contains the entire avatars array, and that you call setState in a loop, …

    But I have no clue what exactly you’re trying to build here and how the code should look like.


    Edit:

    @Meir refactored the function from your answer:

    newUserTypeAvatarsArray = () => {
      const avatars = this.state.avatars.map((avatar, index) => ({ 
        avatar, 
        isChecked: false, 
        index 
      }));
      
      this.setState({
        UsersAvatars: [
          { 
            userType: "everyone", 
            isChecked: false, 
            avatars 
          },
          ...this.state.users_types.map(userType => ({ 
            userType, 
            isChecked: false, 
            avatars 
          }))
        ],
        UsersAvatarsLoading: false,
      });
    }
    
    Reply

Leave a Comment