Ernesto
Ernesto

Reputation: 944

Invoke setState after function

I know that setState is async, but is there anyway (without Redux) to invoke setState after the executing another function before like below:

handleOpenUpdateItem = (item) => {
    const { getImageByItemId } = this.props;
    getImageByItemId(item.id);
    this.setState({ updateMode: true, item });
  };

Greetings!

Upvotes: 0

Views: 1189

Answers (4)

Irek
Irek

Reputation: 197

As it's already mentioned in comments, you could use callbacks to make sure that this.setState is executed after your function finishes (using Promises or async/await would be great options too). This is the examlpe of how it could be implemented:

  getImageByItem = (id, callback) => {
    // Do something here
    // And return your image, or anything you want through callback like so:
    callback(yourImage)
  }

  handleOpenUpdateItem = (item) => {
    const { getImageByItemId } = this.props;
    getImageByItemId(item.id, (image) => {
      this.setState({ updateMode: true, item });
    });
  };

So you change your getImageByItem function to include callback, and then in the handleOpenUpdateItem you use this callback and setState inside it.

EDIT FOR 2019

As @Levitator Imbalance mentioned below, it's probably better to use Promises, so you could implement it like so:

Without async/await:

getImageByItemId = (id) => {
  return new Promise((resolve, reject) => {
    // Do something with your id/image, then resolve
    resolve()
    // Or reject when some error happens
    reject()
  })
}

  handleOpenUpdateItem = (item) => {
    const { getImageByItemId } = this.props;
    getImageByItemId(id)
      .then(() => {
        this.setState({ updateMode: true, item });
      })
      .catch(() => {
        // ... handle your reject here
      })
  };

Or you could use async/await like so: Async/Await:

getImageByItemId = (id) => {
  return new Promise((resolve, reject) => {
    // Do something with your id/image, then resolve
    resolve()
    // Or reject when some error happens
    reject()
  })
}

handleOpenUpdateItem = async (item) => {
  const { getImageByItemId } = this.props;
  let something = await getImageByItemId(item.id)
  // or just:
  // await getImageByItemId(item.id)
  this.setState({ updateMode: true, item });
};

Upvotes: 1

Vladimir Bogomolov
Vladimir Bogomolov

Reputation: 1794

Turn your handleOpenUpdateItem to an async function. Then you can write synchronous code inside of it.

  async handleOpenUpdateItem(item) {
       const { getImageByItemId } = this.props;
       const item = await getImageByItemId(item.id); // wait for the call to the backend to finish
       this.setState({ updateMode: true, item }); 
  };

Upvotes: 1

Apak
Apak

Reputation: 177

You could make handleOpenUpdateItem async and use await for getImageByItemId.

Upvotes: 0

Madara's Ghost
Madara's Ghost

Reputation: 175098

this.setState() being async means that you cannot normally execute things after it and expect them to happen only after the setState had completed its course. Doing things before the setState and then calling setState (exactly like you did) will work out of the box.

Upvotes: 0

Related Questions