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?
componentWillMount()This method is called just before a component mounts on the DOM or the render method is called. After this method, the component gets mounted. Note: You should not make API calls or any data changes using this. setstate in this method because it is called before the render method.
componentDidUpdate does not get called after the first initial render() lifecycle.
There is no call to ComponentDidMount. It is only called once after the initial render.
Unlike with synchronous, a user visiting pages that utilize the asynchronous mode gets to see the page content without having to wait for the page to display the whole content. The type of rendering mode loads pages independently from the ads.
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.
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 safer 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:
"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."
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.
Finally, I think this image of the modern React lifecycle created 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 after setState
as well as forceUpdate
. See this article from the official React blog about the Bugfix for getDerivedStateFromProps
This interactive version of the React lifecycle diagram created by Wojciech Maj allows you to select React version >16.04 with the latest behavior (still accurate as of React 16.8.6, March 27, 2019). Make sure you check the "Show less common lifecycles" option.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With