如何在axios响应之后使React中的setState同步

时间:2017-09-10 07:06:02

标签: javascript reactjs asynchronous axios setstate

我使用axios发出HTTP请求,在其中我发出另一个HTTP请求,以便添加有关我获得的项目的一些细节。我将它推送到'orders'数组后我需要setState,但它之前就这样做了所以我不能以正确的方式打印它。 它适用于SetTimeout但我想以更专业的方式做到这一点。 我怎么能同步?

fetchOrders(){
    let orders = [];
    let status;
    this.setState({loading:true});
    http.get('/api/amazon/orders')
        .then(response => {
            if (response.status === 200) status = 200;
            orders = response.data;
            orders.map(order => {
                order.SellerSKU = "";
                http.get(`/api/amazon/orders/items/${order.AmazonOrderId}`)
                    .then(res => {
                        order.SellerSKU = res.data[0].SellerSKU;
                    })
                    .catch(error => {
                        console.log(error);
                    })    
            });
            setTimeout( () => {
                this.setState({orders, error: status ? false : true, loading:false})
            }, 1000);
        })
        .catch(error => {
            this.setState({loading:false, error:true});
            console.error(error);
        });
}

3 个答案:

答案 0 :(得分:2)

你似乎在问错误的问题,即如何实现异步同步,而你真的试图推迟设置你的状态,直到一切都完成。 (又名XY Problem

您不需要使setState同步 - 您只需要利用一些承诺链和Promise.all,这样您就可以推迟setState调用,直到所有内容都是结束。

简而言之,您应该能够根据需要对此进行调整,并对响应进行一些转换:

fetchOrders() {
    http.get('/first')
        .then(r => r.data)
        .then(orders => {
            // This wraps the iterable of promises into another promise
            // that doesn't resolve until all the promises in the iterable
            // have finished.
            return Promise.all(orders.map((order) => http.get(`/second/${order.id}`).then(/* transform */))
        })
        .then(transformedOrderPromises => this.setState({ ... }); 
}

答案 1 :(得分:1)

setState可以采用回调函数,在完成mutate状态后,它将执行回调。因此,您可以setState在回调中添加第二个API调用。

这样的事情:

http.get('/api/amazon/orders')
    .then(response => {
        if (response.status === 200) status = 200;
        orders = response.data;
        this.setState({orders, error: status ? false : true, loading:false}, 
          () => {
            orders.map(order => {
              order.SellerSKU = "";
              http.get(`/api/amazon/orders/items/${order.AmazonOrderId}`)
                  .then(res => {
                    order.SellerSKU = res.data[0].SellerSKU;
                  }).catch(error => {
                    console.log(error);
                  })    
        });
    })

请注意,我刚编辑了一个肮脏的方式,可能需要进行一些调整才能使其正常工作。

答案 2 :(得分:-3)

在我的项目中,我伪造了同步setState以避免很多陷阱,使代码更清晰。这是我的所作所为:

class MyComponent extends React.Component {
   // override react's setState
   setState(partialState) {
      const mergedState = { ...this.state, ...partialState };
      this.state = mergedState;
      super.setState(partialState);
   }
}

解释:在调用真setState之前,状态也设置为this.state,以便在实际更新之前对它的任何引用都是正确的。

唯一的缺点是你必须从MyComponent而不是React.Component延伸。