如何处理异步道具和状态

How to deal with asynchronous props and state

我无法完全理解这一点。

我必须传递异步获取的数据。问题是,道具也是异步的。这是组件的简化版本:

import React, { Component }  from 'react'
import CSVLink from 'react-csv'
import generateData from './customApi/generateData

type Props = { job?: JobType | undefined }
type State = { csvData: string[][] }

class MyComponent extends Component<Props, State> {
  state = {
    csvData = [],
  }

  generateCsv = async (jobId: string) => {
    const csvData = await generateData(jobId)
    this.setState({ csvData })
  }

  async componentDidMount() {
    const { job } = this.props
    await this.generateCsv(job.id)
  }

  render() {
    const { csvData } = this.state

    return (
       <CSVLink data={csvData}>
          <p>Download csv</p>
       </CSVLink>
    )
  }
}

export default connectFirestore(
   (db, params) => ({ getJob(db, params.id) })
)

基本上我的道具是通过 API 调用 firestore 获取的,因此加载作业需要一段时间。问题是,当我试图在 async componentDidMount() 中传递 jobId 时,它最终传递了 undefined,因为 job props 尚未加载.

我不会 link 将整个传递状态传递给异步调用业务,但我想不出任何其他方式,我如何将 csvDatagenerateDate() 仅在 Promise 解决后才进行异步调用。

我想最简单的方法是,或许可以检查 componentDidMount() 中的道具是否已经获取?

解决这个问题的正确方法是什么?

您缺少实现设置道具的构造函数

constructor(props){
  super(props);
  this.state = {
     csvData = [],
  };
}

componentDidMount(){
  //This will work
  console.log(this.props.job);
};

如果 job 属性 应该异步,那么异步执行:与其传递一个将来会改变的值,不如传递一个 Promise ,它用 id 解析,而不是按如下方式更改 componentDidMount

componentDidMount() {
    const id = await this.props.job;
    this.generateCsv(id)
}

希望对您有所帮助。

也许您应该更改父组件内的代码,我想您正在那里进行 API 调用,因为您正在向我们展示的该组件中将此数据作为道具传递。

我还假设您正在使用 fetch 命令进行 API 调用,它可以在 API 调用完成加载时触发 .then(()=>{}) 方法,之后您可以更改携带 API 获取数据的组件的状态,然后渲染该子组件。我最近在我的项目中使用的东西是从 API 加载,更新状态并有条件地渲染子组件,它不会知道我进行了 API 调用,因为我正在传递已经加载的数据。通常在等待的时候我会放这样的东西:

if(this.state.dataFetched == null)
   return(<h1>Loading page...</h1>)
else return <childComponent loadedData = {this.state.dataFetched}/>

然后以 this.props.loadedData

的形式访问该数据

不确定这是否是最佳解决方案,但它有效。

我决定使用 componentDidUpdate() 生命周期方法,我在其中比较 props 是否已经更新,一旦更新,我将调用异步函数来生成 csv 数据。

async componentDidUpdate(prevProps: Props) {
  if (prevProps !== this.props && !!this.props) {
    const { job } = this.props
    if (job) {
      await this.generateCsv(job.id)
    }
  }
}

这样,每次 props.job 中的数据发生变化时,我们都会生成新数据,而且我们不会尝试在未定义的情况下调用 generateCsv(),而它仍在从 firestore 中获取。