【问题标题】:ReactJS setState when all nested Axios calls are finished当所有嵌套的 Axios 调用完成时 ReactJS setState
【发布时间】:2018-05-21 19:46:23
【问题描述】:

我在从 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

【问题讨论】:

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


    【解决方案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);
        })
      }
    

    【讨论】:

    • 好的,非常感谢!!!我试图使用 Promise.All 但我对它感到困惑。您的解决方案如我所愿!
    • @JavaEvgen 很高兴我能帮上忙 :)
    【解决方案2】:

    尝试通过添加 async 关键字将 fetchfiles() 函数设置为异步方法。现在,我们必须等到项目获得下载链接,因此添加 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);
    })
    }
    

    我还没有测试过代码,但它应该可以工作。

    【讨论】:

    • 你能解释一下原因吗?
    • 只是因为await 等待承诺。 Array.prototype.forEach 返回未定义。
    • 谢谢。我认为它适用于所有语句。
    • 它适用于某种意义上的任何表达。在这里它将等同于Promise.resolve(undefined).then(/* rest of your code*/),它“有点工作”但不像预期的那样:)
    猜你喜欢
    • 2016-03-30
    • 1970-01-01
    • 2021-01-26
    • 2018-09-06
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 2020-07-12
    相关资源
    最近更新 更多