"Shawn, let's start with an exhaustive example that triggers these methods."
Mike informed.
console.log('Start') // Marks entry point of JS code.
var App = React.createClass({
componentWillMount: function(){
console.log('componentWillMount');
},
componentDidMount: function(){
console.log('componentDidMount');
},
getInitialState: function(){
return { status: true}
},
getDefaultProps: function(){
return {name: 'John'};
},
componentWillReceiveProps: function(nextProps){
console.log('componentWillReceiveProps');
},
shouldComponentUpdate: function(nextProps, nextState){
console.log('shouldComponentUpdate');
return true;
},
componentWillUpdate: function(){
console.log('componentWillUpdate');
},
render: function() { console.log('render');
return <h1 onClick={this.toggleState}>
{this.state.status.toString()}
</h1>
},
componentWillUnmount: function(){
console.log('componentWillUnmount') },
toggleState: function() {
this.setState({status: !this.state.status}) }
});
/* List of methods and signatures for reference
* componentWillMount
* componentDidMount
* componentWillReceiveProps(object nextProps)
* boolean shouldComponentUpdate(object nextProps, object nextState)
* componentWillUpdate(object nextProps, object nextState)
* componentDidUpdate(object prevProps, object prevState)
* componentWillUnmount() /
React.render(<App name='Jane'/>, document.body);
"It simply displays a body with the true text and then on clicking, it changes it to display false." Mike.
"Shawn, to keep things simple, I have added just a simple console.log() method for every life cycle method so that we know it was called. If we do a fresh run, the following is printed:"
"Start"
"componentWillMount"
"render"
"componentDidMount"
"Ah, got it. Basically, the window first printed Start to signal the file has been loaded." Shawn said.
"Correct. Next, it printed out componentWillMount. That's the entry point for our component. This method is called when a component gets mounted on the body for the first time. If you can see, we are calling React.render."
React.render(<App name='Jane'/>, document.body);
This is what triggers componentWillMount. In this method, we can call setState to perform some changes to our internal data. However, that doesn't call a new re-render or this method again.
Next is the actual render method call. This is responsible for the actual component display.
Finally, we have a call to componentDidMount. This is invoked immediately after mounting the component and only once after the component is rendered.
We can make use of this to fetch the dynamic information that we want to display in our component after the initial render of the component.
"Once that's done, we are done with our initial run for the display of a component!"
"Nice." exclaimed Shawn.
"Now, we have added a simple onClick event. This calls this.toggleState, which toggles the current status from true to false and vice versa."
As the state is affected, React re-renders the App component. We can see the method call sequence when this happens, as follows:"
"…"
"shouldComponentUpdate"
"componentWillUpdate"
"render"
"…"
"Ah, nice. It went through another re-render cycle." said Shawn.
"Correct. When the state was changed, React knew it needed to re-render the App component. It calls shouldComponentUpdate first. This method returns true or false indicating React to render the component or not.
"We can also control whether the component should be re-rendered or not even if the state gets updated. This method can return false and then React will not re-render the component even if the state is changed."
shouldComponentUpdate: function(nextProps, nextState){
console.log('shouldComponentUpdate');
return false; // Will not re-render the component.
},
"We can also compare nextProps and nextState to the existing values and then decide whether to re-render."
"Awesome, this means that we could get faster components!" Shawn exclaimed.
"Exactly. By default, it always returns true, to always render on changes."
Mike concluded.
"Next up, componentWillUpdate will get called just before rendering. We can take care of any changes that we would like to do or any housekeeping. One thing to note is that we can't call setState in this method. State updates should be handled elsewhere."
"Oh, ok," Shawn.
"We are only left with componentWillReceiveProps."
componentWillReceiveProps: function(nextProps){
console.log('componentWillReceiveProps');
},
"It receives nextProps, which are the new props that the child component receives from the parent component. This method is not called for initial render. We can update the state or do some other housekeeping work based on the changes in props."
"Nice, Mike. I think I am getting a better hang of this."
"Finally, we have componentWillUnmount. This is called when the component is unmounted from the body. We can use this to release the resources, perform cleanups, unset any timers, and so on."
"Got it."
"Alright! Let's update our component to start fetching the information from https://openlibrary.org/."
"So, what we will be doing is updating the componentDidMount to perform an AJAX call and fetch data to display."
componentDidMount : function(){
$.ajax({
var changeSets = this.mapOpenLibraryDataToChangeSet(data);
this.setState({changeSets: changeSets});
});
}
"Here, we are making a call to http://openlibrary.org/recentchanges.
json?limit=10 and asking for the ten most-recent changes. We will get the data in the following format:"
[{
timestamp: "2015-05-25T19:20:33.981700", changes: [
"We will need to format the data as per our requirements so that it's displayed nicely.
Let's take a look at it:"
mapOpenLibraryDataToChangeSet : function (data) { return data.map(function (change, index) { return {
"Here, we are extracting the timestamp, author information, and description of the change, which is the comment in the change. As the changed time is a timestamp, we have made use of the jQuery.timeago plugin to get desirable display of time, such as 2 minutes ago and so forth. To use this plugin, we need to include it in our HTML head tag." Mike explained.
<script src="jquery.timeago.js" type="text/javascript"></script>
"Looks like it's all coming together." Shawn.
"It is, let's take a look at everything in action, shall we?"
var Heading = React.createClass({
render: function () { var headingStyle = {
backgroundColor: 'FloralWhite', fontSize: '19px'
};
return (<th style={headingStyle}> {this.props.heading} </th>);
} });
var Headings = React.createClass({
render: function () {
var headings = this.props.headings.map(function (name, index) {
return (<Heading key={"heading-" + index}
heading={name}/>);
});
return (<tr className='table-th'> {headings} </tr>);
} });
var Row = React.createClass({
render: function () {
var trStyle = {backgroundColor: 'aliceblue'};
return (<tr style={trStyle}>
var Rows = React.createClass({
render: function () {
var rows = this.props.changeSets.map(function (changeSet, index) {
return (<Row key={index} changeSet={changeSet}/>);
});
return (<tbody>{rows}</tbody>);
} });
var App = React.createClass({
getInitialState: function () { return {changeSets: [];
},
mapOpenLibraryDataToChangeSet: function (data) { return data.map(function (change, index) {
return {
componentDidMount: function () {
$.ajax({
var changeSets = this.mapOpenLibraryDataToChangeSet(data);
this.setState({changeSets: changeSets});
});
},
render: function () {
return (<table className='table'>
<Headings headings={this.props.headings}/>
<Rows changeSets={this.state.changeSets}/>
</table>);
} });
var headings = ['Updated at ', 'Author', 'Change'];
React.render(<App headings={headings} />, document.body);
"Here's our final product!", exclaimed Mike.
"Awesome, I can't wait to see what we build next!" Shawn added.
Another productive day at Adequate. Mike and Shawn, happy with the progress, headed back.
Summary
In this chapter, we looked at how to pass around data in the React components using props and state. We also discussed how and when to use state and props. We looked at how propTypes can be used to validate the props. After that, we discussed the component's life cycle. We discussed about the various life cycle methods and how they can be used. After that, we used these life cycle methods to get real-time data from Open Library API.