I am trying to perform an asynchronous call to an API in the componentWillMount method. Indeed I would like the render
method to executed after the componentWillMount method as I need to pass props
to the component in my render
method.
我试图在componentWillMount方法中对API执行异步调用。实际上我想在componentWillMount方法之后执行render方法,因为我需要将props传递给render方法中的组件。
Here is my code :
这是我的代码:
class TennisSearchResultsContainer extends React.Component {
componentWillMount () {
// TODO: Build markers for the map
// TODO: Check courtsResults object and database for tennis court
this.courtsMarkers = this.props.courtsResults.map((court) => {
return new google.maps.Marker({
position: new google.maps.LatLng(JSON.parse(court.LOC).coordinates[1], JSON.parse(court.LOC).coordinates[0]),
title: court.NAME,
animation: google.maps.Animation.DROP
});
});
}
render () {
return <TennisSearchResults criterias={this.props.criterias} courtsMarkers={this.courtsMarkers} />;
}
}
I don't understand then why my render method seems to do not wait for the asynchronous call to finish and pass undefined props to my child component...
我不明白为什么我的render方法似乎不等待异步调用完成并将未定义的道具传递给我的子组件...
Am I right? And what should I do to fix that? What is the way to handle this?
我对吗?我该怎么做才能解决这个问题?处理这个问题的方法是什么?
1 个解决方案
#1
36
You might need to understand javascript async behavior better. Async means "don't wait". That the task will happen in the background and other code will continue to execute. A good way to manage this is to set state on your component. For example, when you enter componentDidMount
set a loading
state to true
. Then when your async function completes, set that state to false
. In your render
function you can then either display a "loading..." message or the data.
您可能需要更好地理解javascript异步行为。异步意味着“不要等待”。任务将在后台执行,其他代码将继续执行。管理它的一个好方法是在组件上设置状态。例如,当您输入componentDidMount时,将加载状态设置为true。然后,当您的异步函数完成时,将该状态设置为false。在渲染功能中,您可以显示“正在加载...”消息或数据。
Here is some code that shows a simplified example of fetching data async and how you could handle that in React. Open the developer tools in your browser and look at the console output to understand the React lifecycle better.
下面是一些代码,它显示了获取数据异步的简化示例以及如何在React中处理它。在浏览器中打开开发人员工具,查看控制台输出以更好地了解React生命周期。
EDIT: Code has been updated to use the new React Lifecycle recommendations as of April 2018. In summary, I replaced componentWillMount
with the safer componentDidMount
.
编辑:代码已更新为使用自2018年4月起的新React Lifecycle建议。总之,我将componentWillMount替换为更安全的componentDidMount。
It might seem inefficient to update the state after the component has already mounted, as 'componentDIDmount' correctly implies. However, per the official React documentation on componentDidMount:
在组件已经安装之后更新状态似乎效率低下,正如'componentDIDmount'正确暗示的那样。但是,根据componentDidMount上的官方React文档:
"If you need to load data from a remote endpoint, this is a good place to instantiate the network request."
“如果你需要从远程端点加载数据,这是一个实例化网络请求的好地方。”
"Calling setState()
in this method will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render()
will be called twice in this case, the user won’t see the intermediate state."
“在此方法中调用setState()将触发额外的渲染,但它将在浏览器更新屏幕之前发生。这可以保证即使在这种情况下将调用render()两次,用户也不会看到州。”
Here's the complete example code:
这是完整的示例代码:
class MyComponent extends React.Component {
constructor(props) {
super();
console.log('This happens 1st.');
this.state = {
loading: 'initial',
data: ''
};
}
loadData() {
var promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('This happens 6th (after 3 seconds).');
resolve('This is my data.');
}, 3000);
});
console.log('This happens 4th.');
return promise;
}
componentDidMount() {
console.log('This happens 3rd.');
this.setState({ loading: 'true' });
this.loadData()
.then((data) => {
console.log('This happens 7th.');
this.setState({
data: data,
loading: 'false'
});
});
}
render() {
if (this.state.loading === 'initial') {
console.log('This happens 2nd - after the class is constructed. You will not see this element because React is still computing changes to the DOM.');
return <h2>Intializing...</h2>;
}
if (this.state.loading === 'true') {
console.log('This happens 5th - when waiting for data.');
return <h2>Loading...</h2>;
}
console.log('This happens 8th - after I get data.');
return (
<div>
<p>Got some data!</p>
<p>{this.state.data}</p>
</div>
);
}
}
ReactDOM.render(
<MyComponent />,
document.getElementsByClassName('root')[0]
);
And here is the working example on CodePen.
这是CodePen上的工作示例。
Finally, I think this image of the modern React lifecycle by React maintainer Dan Abramov is helpful in visualizing what happens and when.
最后,我认为React维护者Dan Abramov对现代React生命周期的这种形象有助于可视化发生的事情和时间。
#1
36
You might need to understand javascript async behavior better. Async means "don't wait". That the task will happen in the background and other code will continue to execute. A good way to manage this is to set state on your component. For example, when you enter componentDidMount
set a loading
state to true
. Then when your async function completes, set that state to false
. In your render
function you can then either display a "loading..." message or the data.
您可能需要更好地理解javascript异步行为。异步意味着“不要等待”。任务将在后台执行,其他代码将继续执行。管理它的一个好方法是在组件上设置状态。例如,当您输入componentDidMount时,将加载状态设置为true。然后,当您的异步函数完成时,将该状态设置为false。在渲染功能中,您可以显示“正在加载...”消息或数据。
Here is some code that shows a simplified example of fetching data async and how you could handle that in React. Open the developer tools in your browser and look at the console output to understand the React lifecycle better.
下面是一些代码,它显示了获取数据异步的简化示例以及如何在React中处理它。在浏览器中打开开发人员工具,查看控制台输出以更好地了解React生命周期。
EDIT: Code has been updated to use the new React Lifecycle recommendations as of April 2018. In summary, I replaced componentWillMount
with the safer componentDidMount
.
编辑:代码已更新为使用自2018年4月起的新React Lifecycle建议。总之,我将componentWillMount替换为更安全的componentDidMount。
It might seem inefficient to update the state after the component has already mounted, as 'componentDIDmount' correctly implies. However, per the official React documentation on componentDidMount:
在组件已经安装之后更新状态似乎效率低下,正如'componentDIDmount'正确暗示的那样。但是,根据componentDidMount上的官方React文档:
"If you need to load data from a remote endpoint, this is a good place to instantiate the network request."
“如果你需要从远程端点加载数据,这是一个实例化网络请求的好地方。”
"Calling setState()
in this method will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render()
will be called twice in this case, the user won’t see the intermediate state."
“在此方法中调用setState()将触发额外的渲染,但它将在浏览器更新屏幕之前发生。这可以保证即使在这种情况下将调用render()两次,用户也不会看到州。”
Here's the complete example code:
这是完整的示例代码:
class MyComponent extends React.Component {
constructor(props) {
super();
console.log('This happens 1st.');
this.state = {
loading: 'initial',
data: ''
};
}
loadData() {
var promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('This happens 6th (after 3 seconds).');
resolve('This is my data.');
}, 3000);
});
console.log('This happens 4th.');
return promise;
}
componentDidMount() {
console.log('This happens 3rd.');
this.setState({ loading: 'true' });
this.loadData()
.then((data) => {
console.log('This happens 7th.');
this.setState({
data: data,
loading: 'false'
});
});
}
render() {
if (this.state.loading === 'initial') {
console.log('This happens 2nd - after the class is constructed. You will not see this element because React is still computing changes to the DOM.');
return <h2>Intializing...</h2>;
}
if (this.state.loading === 'true') {
console.log('This happens 5th - when waiting for data.');
return <h2>Loading...</h2>;
}
console.log('This happens 8th - after I get data.');
return (
<div>
<p>Got some data!</p>
<p>{this.state.data}</p>
</div>
);
}
}
ReactDOM.render(
<MyComponent />,
document.getElementsByClassName('root')[0]
);
And here is the working example on CodePen.
这是CodePen上的工作示例。
Finally, I think this image of the modern React lifecycle by React maintainer Dan Abramov is helpful in visualizing what happens and when.
最后,我认为React维护者Dan Abramov对现代React生命周期的这种形象有助于可视化发生的事情和时间。