通过旧状态和承诺的结果计算新状态

问题描述 投票:2回答:4

我有一个不支持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语法?


Note (Update):

由于当前答案都包含相同的错误,please read @dhilt answer + responses首先解释了什么是错误。

javascript reactjs promise async-await
4个回答
1
投票

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

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

那你可以做什么:

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

附:因此,从setState函数内部发出请求会导致混淆,并且不会增加任何额外的灵活性。


1
投票

如果问题中的代码是正确的,并且您只想清除async / await以支持传统的return promise.then(...)语法,那么请执行以下操作:

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

以下简化也可能有效:

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

0
投票

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

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

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
    }
  });
}
© www.soinside.com 2019 - 2024. All rights reserved.