在进行异步调用后在哪里设置状态?

时间:2018-01-20 16:46:46

标签: javascript reactjs asynchronous async-await amazon-dynamodb

我试图从dynamo db中提取一些数据,将其存储在我的本地状态,然后用它做事。我可以提取数据,我认为我可能需要处理异步的东西,所以我使用异步等待

async componentDidMount() {
//aws secret key stuff here
const ddb = new AWS.DynamoDB({ apiVersion: '2012-10-08' });
    const res = await ddb.scan(params, (err, data) => {
      if (err) {
        console.log(err, err.stack);
      } else {
        console.log(data);
      }
    });
    this.setState({ products: data })
}

我有几个问题。我基本上想等到扫描完成所以我知道数据已经成功拉出然后我可以设置状态。

首先,linter在呻吟,我不应该在componentDidMount中设置状态,所以我应该在哪里设置它?

其次,是在使用数据之前等待某些请求完成的正确方法吗?

我做了console.log(data),我有this.setState({products: data}),并记录了正确的内容。

但当我尝试迭代我的数据时:

{this.state.products.Items.map((product) => (

我无法读取未定义的地图??

2 个答案:

答案 0 :(得分:1)

在componentDidMount中设置状态会导致额外的渲染。 (reference

  

在此方法中调用setState()将触发额外的渲染,但是   它将在浏览器更新屏幕之前发生。这保证了   即使在这种情况下将调用render()两次,   用户不会看到中间状态。请谨慎使用此模式   因为它经常导致性能问题。但它可以   当您需要测量时,需要模态和工具提示等案例   DOM节点在渲染依赖于其大小或的大小之前   位置。

在某些情况下,您必须在componentDidMount上调用一些API和setState。

我看到你需要改变的两件事。似乎 ddb.scan 作为第二个参数获得回调,因此您不需要承诺的ascyn / await。

在这种情况下,你需要在回调中使用setState。

ddb.scan(params, (err, data) => {
  if (err) {
    console.log(err, err.stack);
  } else {
    console.log(data);
    this.setState({ products: data });
  }
});

如果在其他应用程序中使用Promises,您可以使用async / wait并在等待之后使用setState。

const res = await promisecall();
this.setState(res.stuff);

在访问您的产品阵列之前,您应该检查它是否已存在。

this.state.products.Items
第一个渲染过程中未定义

。 componentDidMount运行并设置它但

this.state.products.Items.map

已经抛出错误。

做类似

的事情
this.state.products && 
this.state.products.Items &&
this.state.products.Items.length > 0 &&
this.state.products.Items.map(etc...)

只有在 this.state.products.Items 存在时才会运行。这样做是为了防止第一次渲染(在componentDidMount中设置状态之前)失败。

答案 1 :(得分:0)

首先:您可以调用异步的componentDidMount中的函数,而不是使componentDidMount异步,这会删除您的linting问题

第二:您不需要等待ddb.scan,因为它会在回调中返回响应。你可以在其中设置State,

第三:由于在渲染后调用componentDidMount,因此初始状态可能为null / undefined,因此您在render方法中会出错。确保将状态初始化为空数组或执行验证

componentDidMount() {
    this.dynamoDBScan();
}

async dynamoDBScan() {
     //aws secret key stuff here
    const ddb = new AWS.DynamoDB({ apiVersion: '2012-10-08' });
    const res = await ddb.scan(params, (err, data) => {
      if (err) {
        console.log(err, err.stack);
      } else {
        this.setState({ products: data })
      }
    });


}

然后在渲染

{
   this.state.products && 
   this.state.products.Items.length > 0 &&
   this.state.products.Items.map((product) => (