所有嵌套的Axios调用完成后,ReactJS setState

时间:2018-05-21 11:36:05

标签: reactjs asynchronous async-await axios es6-promise

我遇到了从forEach循环中的嵌套axios调用更新状态的问题:

constructor(props) {
    super(props);
    this.state = {
      isLoaded: false,
      items: []
    };
    //Binding fetch function to component's this
    this.fetchFiles = this.fetchFiles.bind(this);
  }

  componentDidMount() {
    this.fetchFiles();
  }

  fetchFiles() {
    axios.get('/list')
    .then((response) => {
      var items = response.data.entries;
      items.forEach((item, index) => {
        axios.get('/download'+ item.path_lower)
        .then((response) => {
          item.link = response.data;
        })
        .catch(error => {
          console.log(error);
        })
      });
      this.setState(prevState => ({
        isLoaded: true,
        items: items
      }));
      console.log(this.state.items);
    })
    .catch((error) => {
      console.log(error);
    })
  }

我们的想法是使用它的API(JavaScript SDK)从Dropbox获取所有项目 然后对于每个项目,我还需要调用不同的API端点来获取临时下载链接并将其指定为新属性。只有在所有项目都将附加其链接之后,我才想要setState并渲染组件。有人可以帮忙解决这个问题吗,我花了好几个小时与承诺作斗争:S

2 个答案:

答案 0 :(得分:1)

您可以使用Promise.all等待多个承诺。另请注意,setState是异步的,您不会立即看到更改。你需要传递一个回调。

  fetchFiles() {
    axios.get('/list')
    .then((response) => {
      var items = response.data.entries;

      // wait for all nested calls to finish
      return Promise.all(items.map((item, index) => {
        return axios.get('/download'+ item.path_lower)
          .then((response) => {
            item.link = response.data;
            return item
          });
      }));     
    })
    .then(items => this.setState(prevState => ({
        isLoaded: true,
        items: items
      }), () => console.log(this.state.items)))
    .catch((error) => {
      console.log(error);
    })
  }

答案 1 :(得分:0)

尝试通过添加 async 关键字将fetchfiles()函数作为异步方法。现在,我们必须等到项目获取其下载链接,因此添加 await < / strong>关键字在该行之前使代码等待,直到axios调用完成。

async function fetchFiles() {
axios.get('/list')
.then(async function(response){
  var items = response.data.entries;
  await items.forEach((item, index) => {
    axios.get('/download'+ item.path_lower)
    .then((response) => {
      item.link = response.data;
    })
    .catch(error => {
      console.log(error);
    })
  });
  this.setState(prevState => ({
    isLoaded: true,
    items: items
  }));
  console.log(this.state.items);
})
.catch((error) => {
  console.log(error);
})
}

我还没有对代码进行测试,但它应该可以正常运行。