ReactJS setState, когда все вложенные вызовы Axios завершены - PullRequest
0 голосов
/ 21 мая 2018

У меня проблема с обновлением моего состояния из вложенного вызова axios внутри цикла forEach:

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

Идея состоит в том, чтобы получить все элементы из Dropbox, используя его API (JavaScript SDK), а затем для каждого элемента, который яТакже необходимо вызвать другую конечную точку API, чтобы получить временную ссылку для загрузки и назначить ее в качестве нового свойства.Только после того, как все элементы получат свои ссылки, я хочу установитьState и визуализировать компонент.Может ли кто-нибудь помочь с этим, я провожу уже несколько часов, борясь с обещаниями: S

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Попробуйте сделать функцию fetchfiles () как асинхронный метод, добавив ключевое слово async . Теперь нам нужно подождать, пока элементы получат ссылку для загрузки, поэтому добавьте await ключевое слово перед этой строкой, которое заставляет код ждать до завершения вызова 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);
})
}

Я не проверял код, но он, вероятно, должен работать.

0 голосов
/ 21 мая 2018

Вы можете использовать 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);
    })
  }
...