按旧状态和承诺结果计算新状态

时间:2018-08-23 13:43:43

标签: javascript reactjs promise async-await

我有一个不支持generatorsasync await语法的项目。

我用async await构建了以下代码,因为我看不到其他方法:

 this.setState(async lastState => {
      const newImagesAmount = lastState.images.length + 20;
      const newImages = await this.getImages(this.props.tag, newImagesAmount);
      return {
        images: newImages
      };
    });

为什么?在这种情况下,新状态既由旧状态又由promise的结果构成。

如何将其转换为非async await语法?


注意(更新):

由于两个当前答案都包含相同的错误,因此 please read @dhilt answer + responses 首先说明了哪些错误。

4 个答案:

答案 0 :(得分:1)

如果问题中的代码正确,并且您只想清除异步/等待以支持传统的EXECUTE master.dbo.xp_cmdshell 'bcp "\ select ''adam'', \ ''kev'', \ ''bill'', \ " queryout "\\network\path\file.txt" -t"|" -c -T ' 语法,请执行以下操作:

return promise.then(...)

以下简化也可能有效:

this.setState(lastState => {
    const newImagesAmount = lastState.images.length + 20;
    return this.getImages(this.props.tag, newImagesAmount)
    .then(newImages => ({ 'images': newImages });
});

答案 1 :(得分:1)

首先,不可能在await内使用setState()。不是因为项目的限制,而是因为每个内部带有await的函数都应事先声明为async。并且应使用await表示法或链接的.then()进行调用。因此,传递到.setState的回调应该为async并用await进行调用,但是我们知道React无法以这种方式工作。 React期望普通函数并在没有await.then()的情况下调用它。看起来像func.apply(context, funcArgs)模块中的react-dom。此外,也不会检查它是否返回Promise。

让我们回到您的最终目标。据我了解,这是关于确保加载延迟数据后状态仍然保持一致。这是另一个限制。除了sync XHR(这确实是一种不好的做法)之外,无法暂停所有执行,直到数据到来为止。也就是说:无论您做什么,都无法100%保证state在“请求已发送”和“数据已接收”步骤之间没有发生变异。 await或功能性setState均不允许冻结执行。是的,您的代码仍在引用“ prevState”变量,但它可能不再是实际组件的状态!

那么你可以做什么:

  1. 在将另一个XHR发送到同一终结点之前中止正在进行的XHR(应该适用于读取操作;对于写入操作没有意义)
  2. 在处理响应时解析请求参数,以有效方式将其注入状态(例如,第一个响应用于1..10图像,下一个响应用于11..20-因此您可以处理该响应并将第二个响应注入适当的索引,使前10个仍未初始化)
  3. 设置一些标志以阻止新请求,直到处理完成

P.S。因此从setState函数内部发出请求会引起混乱,并且不会增加任何其他灵活性。

答案 2 :(得分:0)

我认为您可能想要这样的东西

const newImagesAmount = this.state.images.length + 20;
this.getImages(this.props.tag, newImagesAmount).then(newImages => 
  this.setState(prevState => ({
      ..prevState,
      images: newImages
    })
);

首先,您请求一个新图像,并且该请求基于当前状态。然后(到达结果时)更新状态。


更新后的版本可以保护异步逻辑在请求完成之前免受多次执行

if (!this.state.pending) {
  this.setState(lastState => {
    const newImagesAmount = lastState.images.length + 20;
    this.getImages(this.props.tag, newImagesAmount).then(newImages => 
      this.setState(prevState => ({
          ...prevState,
          pending: false,
          images: newImages
        })
    ).catch(() =>
       this.setState(prevState => ({
          ...prevState,
          pending: false
        })
    );
    return {
      ...lastState,
      pending: true
    }
  });
}

答案 3 :(得分:0)

我假设此处的lastState实际上只是更新之前的当前状态。尝试这样的事情:

const imageLength = this.state.images.length + 20
this.getImages(this.props.tag, imageLength)
     .then(newImages => {
     this.setState({images: newImages})
}