score:89

Accepted answer

First off, not sure you want to do this in your componentWillMount, it's better to have it in componentDidMount and have some default states that will update once done with these requests. Second, you want to limit the number of setStates you write because they might cause additional re-renders, here is a solution using async/await:

async componentDidMount() {

  // Make first two requests
  const [firstResponse, secondResponse] = await Promise.all([
    axios.get(`https://maps.googleapis.com/maps/api/geocode/json?&address=${this.props.p1}`),
    axios.get(`https://maps.googleapis.com/maps/api/geocode/json?&address=${this.props.p2}`)
  ]);

  // Make third request using responses from the first two
  const thirdResponse = await axios.get('https://maps.googleapis.com/maps/api/directions/json?origin=place_id:' + firstResponse.data.results.place_id + '&destination=place_id:' + secondResponse.data.results.place_id + '&key=' + 'API-KEY-HIDDEN');

  // Update state once with all 3 responses
  this.setState({
    p1Location: firstResponse.data,
    p2Location: secondResponse.data,
    route: thirdResponse.data,
  });

}

score:0

create array of promise and then use reduce.

/**
 * Runs promises from array of functions that can return promises
 * in chained manner
 *
 * @param {array} arr - promise arr
 * @return {Object} promise object
 */
function runPromiseInSequence(arr, input) {
  return arr.reduce(
    (promiseChain, currentFunction) => promiseChain.then(currentFunction),
    Promise.resolve(input)
  )
}

// promise function 1
function p1(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 5)
  })
}

// promise function 2
function p2(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 2)
  })
}

// function 3  - will be wrapped in a resolved promise by .then()
function f3(a) {
 return a * 3
}

// promise function 4
function p4(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 4)
  })
}

const promiseArr = [p1, p2, f3, p4]
runPromiseInSequence(promiseArr, 10)
  .then(console.log)   // 1200

score:1

This is related to JS's Promises. You can solve it in different ways. The simplest way to me is that you should nest each request starting from first to third. That means starting from the first request, you should put your second axios.get(url) into the first request's .then() and put the third request into the second request's .then().

For promises in general you expect that inside the .then() part promise is resolved and you can have access to the response. So that by nesting, you can solve the problem of being asynchronous in a not so elegant way.

score:3

For simultaneous requests with axios, you can use axios.all() plus axios.spread()

axios.spread() is used to spread the array of arguments into multiple arguments, so that all data can be passed to the function.

Example

const url_1 = '', url_2 = ''; 

axios.all([
  axios.get(url_1), 
  axios.get(url_2)
])
  .then(
     axios.spread((resp1, resp2) => {
       let id_1 = resp1.data.results.place_id
       let id_2 = resp2.data.results.place_id
       let url_3 = ''                          // <---- Build your third URL here
       axios.get(url_3)
         .then((resp3) => {
             // You have all the data available here to useState()
         })
     })
  )
  .catch((error) => console.log(error)) 

score:9

I think you need something like this:

const firstRequest = axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p1)
      .then(response => this.setState({ p1Location: response.data }))  }

const secondRequest = axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p2)
  .then(response => this.setState({ p2Location: response.data }))

const thirdRequest = axios.get('https://maps.googleapis.com/maps/api/directions/json?origin=place_id:' + this.state.p1Location.results.place_id + '&destination=place_id:' + this.state.p2Location.results.place_id + '&key=' + 'API-KEY-HIDDEN')
  .then(response => this.setState({ route: response.data }))


Promise.all([firstRequest, secondRequest])
       .then(() => {
           return thirdRequest
       })

score:12

For better performance and cleaner code:

1. Use promise.all() or axios.all() to execute request1 and request2 at the same time. So request2 will execute without waiting for request1 response. After request1 and request2 return the response, request3 will continue execute based on the returned response data as parameter.
2. Template Strings use back-ticks (``)

async componentDidMount(){
    try{
        const [request1, request2] = await Promise.all([
           axios.get(`https://maps.googleapis.com/maps/api/geocode/json?&address=${this.props.p1}`),
           axios.get(`https://maps.googleapis.com/maps/api/geocode/json?&address=${this.props.p2}`)
        ]);

        const request3 = await axios.get(`https://maps.googleapis.com/maps/api/directions/json?origin=place_id:${request1.data.results.place_id}&destination=place_id:${request2.data.results.place_id}&key=${API-KEY-HIDDEN}`);
        console.log(request3);
    }
    catch(err){
        console.log(err)
    }
}

score:35

Have you used axios.all ? You can try with something similar:

axios.all([axios.get(`firstrequest`),
           axios.get(`secondrequest`),
           axios.get(`thirdrequest`)])
     .then(axios.spread((firstResponse, secondResponse, thirdResponse) => {  
         console.log(firstResponse.data,secondResponse.data, thirdResponse.data);
     }))
     .catch(error => console.log(error));

This will take all your get and will put it inside a response that has to be called with .data like: firstResponse.data

score:54

A little late to the party, but I like this pattern of chaining promises, returning them to keep the promise chain alive.

axios
  .get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p1)
  .then(response => {
    this.setState({ p1Location: response.data });
    return axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p2);
  })
  .then(response => {
    this.setState({ p2Location: response.data });
    return axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p3);
  })
  .then(response => {
    this.setState({ p3Location: response.data });
  }).catch(error => console.log(error.response));

Related Query

More Query from same tag