Axios: объединение нескольких запросов API

Мне нужно связать несколько запросов API от API Карт Google, и я пытаюсь сделать это с помощью Axios.

Вот первый запрос, который находится в компонентеWillMount()

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

Вот второй запрос:

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

Затем у нас есть третий запрос, который зависит от завершения первых двух:

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 }))

Как я могу связать эти три звонка, чтобы третье произошло после первых двух?

Ответы

Ответ 1

Во-первых, не уверен, что вы хотите сделать это в componentWillMount, лучше иметь его в componentDidMount и иметь некоторые состояния по умолчанию, которые будут обновляться после выполнения этих запросов. Во-вторых, вы хотите ограничить количество записываемых наборов состояний, поскольку они могут вызвать дополнительные повторные рендеры, вот решение с использованием 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,
  });

}

Ответ 2

Вы использовали axios.all? Вы можете попробовать что-то подобное:

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));

Это займет весь ваш get и поместит его в ответ, который должен быть вызван с.data: firstResponse.data

Ответ 3

Немного поздно на вечеринку, но мне нравится этот образец цепочки обещаний, возвращая их, чтобы сохранить цепочку обещаний в живых.

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));

Ответ 4

Я думаю, вам нужно что-то вроде этого:

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
       })

Ответ 5

Для лучшей производительности и более чистого кода:

1. Используйте execute.all() или axios.all() для одновременного выполнения запросов1 и request2. Поэтому request2 будет выполняться без ожидания ответа request1. После того, как запрос1 и request2 вернут ответ, request3 продолжит выполнение на основе возвращаемых данных ответа в качестве параметра.
2. Шаблоны строк используют обратные тики ('')

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)
    }
}

Ответ 6

Это связано с обещаниями JS. Вы можете решить его по-разному. Самый простой способ для меня состоит в том, что вы должны вложить каждый запрос, начиная от первого до третьего. Это означает, что, начиная с первого запроса, вы должны поместить второй axios.get(url) в первый запрос .then() и поместить третий запрос во второй запрос .then().

Для обещаний в целом вы ожидаете, что внутри обещания части .then() будет разрешено, и вы можете получить доступ к response. Так что, вложенность, вы можете решить проблему асинхронности не так элегантно.