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.
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...
Am I right? And what should I do to fix that? What is the way to handle this?
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 aloading
state totrue
. Then when your async function completes, set that state tofalse
. In yourrender
function you can then either display a "loading..." message or the data.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.
EDIT: Code has been updated to use the new React Lifecycle recommendations as of April 2018. In summary, I replaced
componentWillMount
with the safercomponentDidMount
.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:
"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 therender()
will be called twice in this case, the user won’t see the intermediate state."Here's the complete example code:
And here is the working example on CodePen.
Finally, I think this image of the modern React lifecycle by React maintainer Dan Abramov is helpful in visualizing what happens and when.
NOTE that as of of React 16.4, this lifecycle diagram has a small inaccuracy:
getDerivedStateFromProps
is now also called aftersetState
as well asforceUpdate
. See this article from the official React blog about the Bugfix for getDerivedStateFromPropsThis interactive version of the React lifecycle diagram allows you to select React version 16.04 with the latest behavior. Make sure you check the "Show less common lifecycles" option.