简体   繁体   English

ReactJS:在.map()语句后执行带有Ajax调用的代码

[英]ReactJS: execute code after .map() statement with ajax call in it is finished

I'm stuck at a problem with my twitch tv api app for freecodecamp. 我在freecodecamp的twitch电视api应用程序中遇到了问题。

I have a .map() statement with an ajax call in it. 我有一个带有ajax调用的.map()语句。 And I push the data I get from the call into an array. 然后,我将从调用中获得的数据推送到数组中。

I want to set the state of the app to the array after the whole .map() loop is finished but somehow the Array is always empty when I access it outside of .map() 我想在整个.map()循环完成后将应用程序的状态设置为数组,但是以某种方式,当我在.map()之外访问它时,该数组始终为空

Here is the code I tried. 这是我尝试的代码。

getData() {
  let tempArray= [];
  let self = this;
  STREAMER.map(function(streamer, i) {
    $.ajax({
      url: URL + streamer,
      success: (data) => {
        tempArray.push(data);
      },
      dataType: "jsonp"
    })
  });
  this.setState({data: tempArray});
}

I got the feeling that the problem is that the ajax call is asynchronous obv. 我感觉到问题在于ajax调用是异步obv。 But I thought since I call the this.setState() method outside of the .map() loop which should be synchronous everything should be fine but isn't. 但是我想,因为我在.map()循环之外调用this.setState()方法,该方法应该是同步的,所以一切都应该很好,但事实并非如此。

The Ajax call isn't the problem btw. 顺便说一句,Ajax调用不是问题。 If I log the data inside of the success method everything is exactly how I like it. 如果我将数据记录在成功方法中,那么一切都将完全符合我的意愿。

Any Ideas? 有任何想法吗?

Use your .map() call to return the promises from all the $.ajax() calls. 使用您的.map()调用从所有$.ajax()调用中返回承诺。 You can then use $.when() to wait for them to complete: 然后,您可以使用$.when()等待它们完成:

getData() {
  let tempArray= [];
  let self = this;
  $.when.apply($, STREAMER.map(function(streamer, i) {
    return $.ajax({
      url: URL + streamer,
      success: (data) => {
        tempArray.push(data);
      },
      dataType: "jsonp"
    })
  }).then(function() {}
    self.setState({data: tempArray});
  });
}

The returned promises will be gathered up into an array by .map() . 返回的Promise将通过.map()收集到一个数组中。 The returned array is then passed via .apply() into $.when() . 然后,返回的数组通过.apply()传递到$.when() .apply() $.when() That'll manage waiting for all the promises, and your .then() callback will be invoked when they're all done. 这样可以等待所有的promise,并且当它们全部完成时,将调用.then()回调。

If it's at all possible, I suggest you look into the possibility of doing the iteration work at the server and providing a single HTTP API that processes a group of items and returns an aggregate result. 如果有可能,建议您研究在服务器上进行迭代工作并提供单个HTTP API来处理一组项目并返回汇总结果的可能性。 HTTP requests take time, and browsers will only do a limited number of them concurrently. HTTP请求需要时间,浏览器只能同时执行有限数量的请求。 One issue in particular with this approach is that the order of the "temp" array will not necessarily match the order of the original array. 这种方法特别存在的一个问题是“临时”数组的顺序不一定与原始数组的顺序匹配。 That is, when the process is done, tempArray[2] may or may not contain the result from the ajax call for STREAMER[2] . 也就是说,完成该过程后, tempArray[2]可能包含也可能不包含来自对STREAMER[2]的ajax调用的结果。 There's no guarantee that the HTTP requests will complete in the order that they were issued; 不能保证HTTP请求将按照发出的顺序完成。 in fact if you're doing more than a few, then it's very very likely that they'll complete out of order. 实际上,如果您要完成的工作不止几个,那么很有可能它们会无序完成。

SIMPLE SOLUTION 简单的解决方案

The setState() function should be called inside the success callback of async ajax request. 应该在异步ajax请求的成功回调内部调用setState()函数。

getData() {
  let tempArray= [];
  let self = this;
  STREAMER.map(function(streamer, i) {
    $.ajax({
      url: URL + streamer,
      success: (data) => {
        tempArray.push(data);
        if(i === STREAMER.length - 1) {
          self.setState({data: tempArray});
        }
      },
      dataType: "jsonp"
    })
  });
}

USE PROMISE 使用承诺

When all ajax requests are successful, resolve the Promise and setState inside resolve() . 当所有的ajax请求都成功时,在resolve()解析PromisesetState

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM