Search code examples
javascriptreactjspromisechaining

Linking functions with Promises in React


I've been fighting with updating the state in Reactjs in the correct order for the past few days which made me realise I need to handle my asynchronous functions properly. Unfortunately, it turns out I don't fully understand Promise() either. I am struggling to make the Promise chain work correctly as my third function is never called in the example below.

componentDidMount() {
    this.mockOne()
    .then(this.mockTwo())
    .then((successMessage) => {
      console.log('successMessage: ', successMessage);
      this.mockThree()
    });
  }

  mockOne() {
    return new Promise((resolve, reject) => {
      console.log('mockOne')
    })
  }

  mockTwo() {
    return new Promise((resolve, reject) => {
      setTimeout(function() {
        console.log('mockTwo')
      }, 2000)
    })
    .catch(err => console.log('There was an error in mockTwo:' + err));
  }

  mockThree() {
    return new Promise((resolve, reject) => {
      console.log('mockThree')
    })
  }

console output

I've tried the instructions in the MDC but either mockThree() is called immediately before mockTwo() has a chance to respond or mockThree() isn't called at all.

Any help to get this working will be greatly appreciated.

The answer provided worked perfectly until I tried to chain a few more asynchronous functions. Can anyone help me understand why my first function causes the workflow to pause but the next three functions are completed immediately please?

componentDidMount() {

    this.mockOne()
      .then(successMessage => {
        this.mockTwo();
      })
      .then(successMessage => {
        this.mockThree();
      })
      .then(successMessage => {
        this.mockFour();
      });
  }

  mockOne() {
    return new Promise((resolve, reject) => {
      console.log("mockOne");
      setTimeout(function() {
        resolve("Test success message");
      }, 2000);
    }).catch(err => console.log("There was an error in mockOne:" + err));
  }

  mockTwo() {
    return new Promise((resolve, reject) => {
      console.log("mockTwo");
      setTimeout(function() {
        resolve("Test success message");
      }, 2000);
    }).catch(err => console.log("There was an error in mockTwo:" + err));
  }

  mockThree() {
    return new Promise((resolve, reject) => {
      console.log("mockThree");
      setTimeout(function() {
        resolve("Test success message");
      }, 2000);
    }).catch(err => console.log("There was an error in mockThree:" + err));
  }

  mockFour() {
    return new Promise((resolve, reject) => {
      console.log("mockFour");
      setTimeout(function() {
        resolve("Test success message");
      }, 2000);
    }).catch(err => console.log("There was an error in mockFour:" + err));
  }

Solution

  • You have to call the resolve function for the promise to become fulfilled. You also need to make sure you are not invoking this.mockTwo() straight away, but instead just give the function this.mockTwo to then.

    class App extends React.Component {
      componentDidMount() {
        this.mockOne()
          .then(this.mockTwo)
          .then(successMessage => {
            console.log("successMessage: ", successMessage);
            this.mockThree();
          });
      }
    
      mockOne() {
        return new Promise((resolve, reject) => {
          console.log("mockOne");
          resolve();
        });
      }
    
      mockTwo() {
        return new Promise((resolve, reject) => {
          console.log("mockTwo");
          setTimeout(function() {
            resolve("Test success message");
          }, 2000);
        }).catch(err => console.log("There was an error in mockTwo:" + err));
      }
    
      mockThree() {
        return new Promise((resolve, reject) => {
          console.log("mockThree");
          resolve();
        });
      }
    
      render() {
        return null;
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    
    <div id="root"></div>