Axios:链接多个API请求

时间:2017-05-25 14:23:17

标签: reactjs react-native axios

我需要从Google Maps API链接一些API请求,而我正在尝试使用Axios。

这是第一个请求,它位于componentWillMount()

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

如何将这三个调用链接起来,以便第三个调用发生在前两个调用之后?

7 个答案:

答案 0 :(得分:24)

首先,不确定是否要在componentWillMount中执行此操作,因为在完成所有这些操作后,您的组件才会呈现,最好将其放在componentDidMount中,并且有一些默认状态完成这些请求后将更新。其次,你想限制你写的setStates的数量,因为它们可能会导致额外的重新渲染,这是一个使用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,
  });

}

答案 1 :(得分:11)

你用过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

答案 2 :(得分:5)

聚会晚了一点,但是我喜欢这种将诺言链接起来的模式,将它们返回以使诺言链保持活力。

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

答案 3 :(得分:4)

我认为你需要这样的东西:

json_encode

答案 4 :(得分:1)

以获得更好的性能和更简洁的代码

1.使用promise.all()或axios.all()同时执行request1和request2。因此request2将在不等待request1响应的情况下执行。 request1和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)
    }
}

答案 5 :(得分:0)

这与JS的Promises有关。你可以用不同的方式解决它。对我来说最简单的方法是你应该从第一个到第三个嵌套每个请求。这意味着从第一个请求开始,您应该将第二个axios.get(url)放入第一个请求的.then(),并将第三个请求放入第二个请求的.then()

对于一般的承诺,您希望.then()部分承诺内部得到解决,您可以访问response。因此,通过嵌套,您可以以不那么优雅的方式解决异步问题。

答案 6 :(得分:0)

创建承诺数组,然后使用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