无法使用React中追踪的Promises返回的数据进行setstate

时间:2017-12-31 10:31:03

标签: javascript reactjs promise

我使用React和promises,我有2个函数。第一个返回数据。我调用第二个函数时使用的数据 - 我在其中发出get请求(调用一个函数,我正在进行实际的get请求)。我尝试存储来自第二个函数调用集状态的响应,但是,它总是未定义或我收到错误:

  

无法设置未定义的状态。

在我的代码中 - 当我记录&#39;测试&#39;时,它也是未定义的,所以某种程度上该值不存储/或者可能不会返回任何地方,但我不知道该怎么做。< / p>

class App extends React.Component {
  handleInput() {
    multipleAirports(this.state.input.origin.value).then(response => {
        var result = [];
        var test = [];
        var input = this.state.input;
        for (var i = 0; i < response.Airports.length; i++) {
            result.push(anyDestinationData(response.Airports[i].code, input.departuredate, input.returndate, input.maxfare))

           return Promise.all(result).then(function (results) {
                var data = [];
                results.forEach(function (item) {
                    data.push({
                        [item.data.OriginLocation]: item.data.FareInfo
                    })

                });
                test = data;
            })
        }
        this.setState({
            flightData: test
        })
    })
        .then(response => {
            console.log("resreeeee", response)

        })
  }
}

4 个答案:

答案 0 :(得分:1)

这两部分存在问题:

  • 在循环中调用并返回Promise.all

    for (var i = 0; i < response.Airports.length; i++) {
       result.push(anyDestinationData(response.Airports[i].code, input.departuredate, input.returndate, input.maxfare))
    
       return Promise.all(result).then(function (results) {
    

    遇到return语句后,函数的执行将不会继续。将它置于没有条件的循环中将始终导致函数在第一次迭代中停止执行(假设满足循环条件)。

    在您的情况下,result数组在传递给Promise.all之前将始终包含一个元素,并返回结果承诺。

  • 引用错误的this内部函数 - 其值在函数调用中确定,而不是函数定义(不是箭头函数的情况) )。

    return Promise.all(result).then(function(results) {
       //...
       this.setState({
    

这应该有效:

class App extends React.Component {
  handleInput() {
    multipleAirports(this.state.input.origin.value).then( response => {
      // Populate the array.
      const result = response.Airports.map(airport => anyDestinationData(airport.code, input.departuredate, input.returndate, input.maxfare));

      // Pass it to `Promise.all` and return it.
      return Promise.all(result).then( results => {
        const data = results.map(item => ({ [item.data.OriginLocation]: item.data.FareInfo }))
        this.setState({
          flightData: data
        })
      })   
    })
    .then(response => {
      console.log("resreeeee", response)
    })
  }
}

注意我已将for循环替换为.map次调用,将var替换为const / let s,因为您已使用ES7功能

答案 1 :(得分:1)

由于书面this.setState()因为多种原因而无法满足您的需求:

  • for循环内部返回不仅会终止循环,还会终止整个.then()回调。
  • Promise.all(result).then(...)需要在循环之外。
  • this.setState需要位于Promise.all(result).then(...)回调中。

这里的目标比首次出现的目标要简单得多。

您寻求的基本模式是:

myFn() {
    // return a Promise to myFn's caller - shouldn't hurt even if not necessary
    return doSomethingAsync()
    .then(response => {
        // map `responses` to an array of promises
        var promises = response.map(item => doSomethingElseAsync(item));
        // aggregate `promises` and return a promise that delivers an array of results from doSomethingElseAsync().
        return Promise.all(promises);
    })
    .then(data => {
        // do something with <Array> `data`
        this.setState({
            flightData: data.map(/* some transform of `data` */)
        });
        return data; // optional - deliver `data` (via the returned Promise) to myFn's caller.
    });
}

完整:

class App extends React.Component {
    handleInput() {
        var input = this.state.input;
        return multipleAirports(input.origin.value)
        .then(response => {
            // map `response.Airports` to an array of promises (originally named `result`)
            var promises = response.Airports.map(airport => anyDestinationData(
                airport.code,
                input.departuredate,
                input.returndate,
                input.maxfare
            ));
            // aggregate `promises` and return a Promise that delivers an array of flights (presumably).
            return Promise.all(promises);
        })
        .then(flights => {
            // map `flights` to array of specialised objects
            var data = flights.map(item => {
                return { [item.data.OriginLocation]: item.data.FareInfo };
            });
            this.setState({
                flightData: data
            });
            return data; // optional - make `data` (or `flights`?) available to handleInput's caller.
        });
    }
}

注意:

  • 承诺提供数据虽然有时很方便,但很少需要通过&#34;传递&#34;通过外部成员的数据。问题var test是不必要的。
  • Array.prototype.map()制作非常简洁的代码(两次)。

答案 2 :(得分:0)

为什么你在for循环中返回了Promise.all?使用您需要的内容填充result,然后将其用于Promise.all()。当这些承诺中的每一个都得到解决时,您将在then()中收到输出。我假设anyDestinationData是一个承诺。还要在任何地方添加控制台,以便在它成为undefined时进行检查。

答案 3 :(得分:0)

&#13;
&#13;
class App extends React.Component {
    handleInput = () => {
        const {
          input,
          input: { origin: {
            value
          }}
        } = this.state;

        multipleAirports(value)
          .then((response) => {
              const results = response.Airports.map(airport => anyDestinationData(airport.code, input.departuredate, input.returndate, input.maxfare));

              return Promise.all(results)
                .then((result) => {
                  results.map((item) => {
                    const data = result.map(item => ({
                      [item.data.OriginLocation]: item.data.FareInfo
                    }))
                    this.setState({
                      flightData: data
                    })
                  })
                })
                .then(response => {
                  console.log("resreeeee", response)
                })
            }
          }
&#13;
&#13;
&#13;

我稍微修改了你的代码,请查看是否有效。我将Promise.all从循环中取出,然后在承诺内部setState