如何处理异步道具和状态
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 将整个传递状态传递给异步调用业务,但我想不出任何其他方式,我如何将 csvData
从 generateDate()
仅在 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 中获取。
我无法完全理解这一点。
我必须传递异步获取的数据。问题是,道具也是异步的。这是组件的简化版本:
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 将整个传递状态传递给异步调用业务,但我想不出任何其他方式,我如何将 csvData
从 generateDate()
仅在 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 中获取。