1

The closest answer I could find was this, which didn't help since I need to setState: How do I run a function after using array.map?

I think the answer should be simple, but I'm pretty new to Javascript. I'm trying to move the setState for isLoading to AFTER I've pulled all of the profiles.

componentDidMount() {
    console.log('MatchesScreen init props: ', Object.keys(this.props))

    Object.keys(this.props.profile.profile.matches).map((username) => {
      console.log('match', username)
      url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username
      fetch(url, {
        method: 'GET',
      })
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({
          isLoading: false,
        })
        this.props.addMatch(responseJson)
      })
      .catch((error) =>{
        console.error(error);
      })
    })
  }

I've tried various things like appending a .then() to the map function, but so far no luck.

Matt Takao
  • 2,406
  • 3
  • 16
  • 30

3 Answers3

3

You could return each promise inside the .map() function, which would leave you with an array of promises. Once you have that, you can use Promise.all() to wait for all the promises in the array to resolve.

componentDidMount() {
    console.log('MatchesScreen init props: ', Object.keys(this.props))

    // Put all promises into an array
    const promisesArray = Object.keys(this.props.profile.profile.matches).map((username) => {
        console.log('match', username)
        url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username;
        // Return each promise
        return fetch(url, {
                method: 'GET',
            })
            .then((response) => response.json())
            .then((responseJson) => {
                this.props.addMatch(responseJson)
            })
            .catch((error) =>{
                console.error(error);
            });
    });

    // Wait for all promises in array to resolve
    Promise.all(promisesArray)
        .then(() => {
            // This will execute once all promises have resolved
            this.setState({
                isLoading: false,
            });
        })
        .catch(e => console.error(e));
}
Emilio Venegas
  • 546
  • 5
  • 22
0

Try using the async/await pattern as follows:

async componentDidMount() {
...
    Object.keys(this.props.profile.profile.matches).map((username) => {
    ...
      await fetch(url, {
      ...

then move your setState method into its own callback, which you can call in your .then() statements following your fetch.

I like this reference: https://alligator.io/js/async-functions/

Abe
  • 4,500
  • 2
  • 11
  • 25
0

Try wrapping the Object.keys() in a while loop with an if statement at the end.

var profilesMatched = 0;
while(profilesMatched < Object.keys(this.props.profile.profile.matches).length){
    Object.keys(this.props.profile.profile.matches).map((username) => {
      console.log('match', username)
      url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username
      fetch(url, { method: 'GET', })
      .then((response) => {response.json()})
      .then((responseJson) => {
        this.props.addMatch(responseJson);
        profilesMatched++;
      })
      .catch((error) => {
        console.error(error);
      });
    });
    if(profilesMatched == Object.keys(this.props.profile.profile.matches).length){
        this.setState({
          isLoading: false,
        })
    }
}
Raymond Mutyaba
  • 950
  • 1
  • 9
  • 14