ReactJS setState when all nested Axios calls are finished

我的梦境 提交于 2020-05-14 12:16:04

问题


I have a problem with updating my state from nested axios call inside forEach loop:

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

The idea is to get all items from Dropbox using it's API (JavaScript SDK) and then for each item I also need to call different API endpoint to get a temporary download link and assign it as a new property. Only after all items will get their links attached I want to setState and render the component. Could somebody please help with this, I spend already multiple hours fighting with promises :S


回答1:


You could use Promise.all to wait for multiple promises. Also keep in mind that setState is async and you wont see immediate changes. You need to pass a callback.

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



回答2:


Try making the fetchfiles() function as an asynchronous method by adding the async keyword.Now, we have to wait till the items to get their download link, so add a await keyword before that line which makes the code to wait till the axios call gets completed.

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

I haven't tested the code, but it should probably work.



来源:https://stackoverflow.com/questions/50448013/reactjs-setstate-when-all-nested-axios-calls-are-finished

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!