Pure Components In React

If you work with React lifecycle hooks and states then you know very well whenever we use the setState method to change the state of a React component then the React component always re-renders and shows the new changes on view. Using the “setState” method we can change the state of any React component. When a state of any component changes it will call the “render” method again and refresh the view again.

I think this is the best and required approach to React. Because if we want to make the new changes visible, then this “setState” method will be used. If we make any change in the property (props) of a component, the component will not render because props are the read-only type and we can’t change the values of props in the component. I know the re-rendering approach of React component (when state changes) is one of the best features of React. However, sometimes, this best feature generates issues in terms of performance for React applications.  

Let’s take an example and get a better understanding. I have a component and below is the context for this component.

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3.     
  4. class Main extends React.Component {      
  5.     constructor(props) {    
  6.       super(props);            
  7.       this.state = {    
  8.          city: "Alwar",    
  9.       }    
  10.    }   
  11.      
  12.    componentDidMount(){  
  13.        setInterval(()=>{  
  14.            this.setState(()=>{  
  15.                return { city: "Alwar"}  
  16.            })  
  17.        },2000)  
  18.    }  
  19.    render() {    
  20.        console.log('Main Component render');    
  21.       return (    
  22.           <div>      
  23.          <h2>      
  24.             {this.state.title}     
  25.          </h2>      
  26.          <p>User Name: {this.props.name}</p>    
  27.          <p>User Age: {this.props.age}</p>    
  28.          </div>    
  29.       );      
  30.    }    
  31.        
  32. }      
  33. Main.propTypes ={    
  34.        name:PropTypes.string.isRequired,    
  35.        age:PropTypes.number.isRequired    
  36.    }    
  37.     
  38. Main.defaultProps = {    
  39.   name: 'Pankaj Kumar Choudhary',    
  40.   age: 24    
  41. };    
  42.       
  43. export default Main;   

In the above lines of code, I define some initial props and a state. In “componentWillMount” life cycle hooks I use the setInterval method that will repeat the interaction after each 1 second and use the “setState” method of the component. I saved the above code; see the below output in the browser.

React

Because we are using the “setState” method, so “setState” method every time calls the “render” function of the component and resets the view for the component.  Now the question arises, do we really need to re-render the component each time?  If you check above example then you will find that we call the “setState” method each time but there was not any change between the new and previous state; after that it calls the render method of the component. Does it make any sense?


The actual implementation should be like this - the rendering method should be called whenever there is any difference between previous and new state and props. But the issue is that the React component doesn’t handle this. Now, what will be the solution to resolve this issue? There are two methods; the first one is that we handle this scenario at our end using the “shouldComponentUpdate” life cycle and the second one is using the “Pure Component”. I talk about the “Pure Component” later but first, we should learn how we can handle this at our end.

Now, I made some changes to the previous code and new updated code is below.

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3.     
  4. class Main extends React.Component {      
  5.     constructor(props) {    
  6.       super(props);            
  7.       this.state = {    
  8.          city: "Alwar",    
  9.       }    
  10.    }   
  11.      
  12.    componentDidMount(){  
  13.        setInterval(()=>{  
  14.            this.setState(()=>{  
  15.                return { city: "Alwar"}  
  16.            })  
  17.        },1000)  
  18.   
  19.        setInterval(()=>{  
  20.         this.setState(()=>{  
  21.             return { city: "Jaipur"}  
  22.         })  
  23.     },6000)  
  24.    }  
  25.   
  26.    shouldComponentUpdate(nextProps,nextState){  
  27.        return nextState.city!=this.state.city?true:false;  
  28.    }  
  29.    render() {    
  30.        console.log('Main Component render '+Date.now());    
  31.       return (    
  32.           <div>      
  33.          <h2>      
  34.             {this.state.title}     
  35.          </h2>      
  36.          <p>User Name: {this.props.name}</p>    
  37.          <p>User Age: {this.props.age}</p>    
  38.          </div>    
  39.       );      
  40.    }    
  41.        
  42. }      
  43. Main.propTypes ={    
  44.        name:PropTypes.string.isRequired,    
  45.        age:PropTypes.number.isRequired    
  46.    }    
  47.     
  48. Main.defaultProps = {    
  49.   name: 'Pankaj Kumar Choudhary',    
  50.   age: 24    
  51. };    
  52.       
  53. export default Main;   

Output

React

In the above code, I also implemented the “shouldComponentUpdate” lifecycle hooks, this method is called before the “render” method call. In this method, we will check if the component will render or not. If the return value of this component is ‘True’ then the component will re-render otherwise not. In this method, we can implement our logic and tell the component if it will be re-rendered or not. So I checked the “city” property of current and nextState, if there is any difference b/w city property of both state then “shouldComponentUpdate” method returns true otherwise false.

We can prevent the “unnecessary” rendering of the component. We prevent this rendering at our end but React also has another option that is “Pure Component”.

What is Pure Component?

The pure component is the same as a component that handles the shouldComponentUpdate method for us as we did in the previous example. Whenever the state or props of the component changes it does a shallow comparison and checks if that component will re-render or not.  Pure component did the same task for us that we did in shouldComponentUpdate manually but does it internally and increases the performance of our application. A simple component doesn’t compare the previous and next state instead of rendering the component whenever  the“shouldComponentUpdate” method is called. Let’s update our previous example using the Pure Component.

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3.     
  4. class Main extends React.PureComponent {      
  5.     constructor(props) {    
  6.       super(props);            
  7.       this.state = {    
  8.          city: "Alwar",    
  9.       }    
  10.    }   
  11.      
  12.    componentDidMount(){  
  13.        setInterval(()=>{  
  14.            this.setState(()=>{  
  15.                return { city: "Alwar"}  
  16.            })  
  17.        },1000)  
  18.   
  19.        setInterval(()=>{  
  20.         this.setState(()=>{  
  21.             return { city: "Jaipur"}  
  22.         })  
  23.     },6000)  
  24.    }  
  25.   
  26.      
  27.    render() {    
  28.        console.log('Main Component render '+Date.now());    
  29.       return (    
  30.           <div>      
  31.          <h2>      
  32.             {this.state.title}     
  33.          </h2>      
  34.          <p>User Name: {this.props.name}</p>    
  35.          <p>User Age: {this.props.age}</p>    
  36.          </div>    
  37.       );      
  38.    }    
  39.        
  40. }      
  41. Main.propTypes ={    
  42.        name:PropTypes.string.isRequired,    
  43.        age:PropTypes.number.isRequired    
  44.    }    
  45.     
  46. Main.defaultProps = {    
  47.   name: 'Pankaj Kumar Choudhary',    
  48.   age: 24    
  49. };    
  50.       
  51. export default Main;     

Output

React

What is Shallow Comparison?

If you noticed, for Pure Component I used “Shallow Comparison” term, actually Pure Components do the Shallow comparison instead of deep comparison.  A shallow comparison means when checking the previous state and props if the value is a primitive type then it only checks or compares their values but props or state are a complex type like an object and array then it checks their reference type. In deep checking reference values are compared instead. Let’s take an example,

  1. var studentObj=function(name,age)  
  2.         {this.name=name;  
  3.         this.age=age};  
  4. var obj1=new studentObj('pankaj',24);  
  5. var obj2=obj1;  
  6.   
  7. //compare both object  
  8. obj1==obj2  //output: true  
  9.   
  10. //create another object  
  11.   
  12. var obj3=new studentObj('pankaj',24)  
  13. //compare both object  
  14. obj2==obj3  //output: false  because in complex type object rference are checked that are not same in this case  
  15.   
  16. //check the value of both object  
  17.  obj3.name==obj2.name  //output: true because in primitive type value are checked that are same in this case  

Never Mutate the Props and State in Parent Component

If you have any pure child component then never mutate the object and array in props or state of the parent component. The reason is that if you update the object or array into parent component and you pass this object or array to pure child component then child component will not re-render, because as I explained earlier Pure Component checks the reference of the props and state. Because you update (mutate) the object or array and reference is not changed, the child component can’t detect the changes. Let’s take an example.

I created another component and named this component as “child.jsx." This child component is pure in nature.

child.jsx

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3.     
  4. class Child extends React.PureComponent {      
  5.     constructor(props) {    
  6.       super(props);  
  7.    }   
  8.       
  9.    render() {    
  10.        console.log('Child Component render '+Date.now());    
  11.       return (    
  12.           <div>      
  13.           <p>Props Values is {this.props.childProps}</p>  
  14.          </div>    
  15.       );      
  16.    }    
  17.        
  18. }      
  19. Child.propTypes ={    
  20.     childProps:PropTypes.array.isRequired,    
  21.    }      
  22.       
  23. export default Child;     

Now, we use this component into “Main.jsx” component that will be the parent component.

main.jsx

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3. import Child from '../child/child';    
  4. class Main extends React.Component {      
  5.     constructor(props) {    
  6.       super(props);            
  7.       this.state = {   
  8.         name:'Pankaj',  
  9.          city: "Alwar",  
  10.          data:[Date.now()]    
  11.       }    
  12.    }   
  13.   
  14.    addData(){  
  15.        var arrayData=this.state.data;  
  16.        arrayData.push(Date.now());  
  17.        this.setState({data:arrayData});  
  18.    }  
  19.      
  20.   
  21.      
  22.    render() {    
  23.        console.log('Main Component render');    
  24.       return (    
  25.           <div>          
  26.          <p>User Name: {this.state.name}</p>    
  27.          <p>User City: {this.state.city}</p>  
  28.          <p>User Data: {this.state.data.join("  ,")}</p>   
  29.          <Child childProps={this.state.data}></Child>  
  30.          <input type="button" value="UpdateData" onClick={this.addData.bind(this)} />   
  31.          </div>    
  32.       );      
  33.    }    
  34.        
  35. }      
  36.  export default Main;     

In “main.jsx” component I defined the state of component. The state of “main.jsx” component contains three attributes (name, city, and data). The type of “data” attribute is Array type and we are passing this attribute as a property of the “Child” component. In this component, we also create a button and on click event of this button, we update the state of the component (update data attribute).

In “child” component we are displaying the value of “data” property. Now what will happen as we click on the “UpdateData” button  is it will update the state of “Main” component and “Main” component will re-render but the child component will never re-render. Because the reference to “data” property is not changed.

React

If you define the child component as a simple component instead of the “pure component” then child component will start to re-render.

 

React

So, never mutate the array type and object type property; instead of this always assign a new value.

React

Now, make some changes to “Main.jsx” component as highlighted above, after saving the changes now you will find that on each button click child it is also rendering because now each type of reference of the “data” property is also changing.

React

Don’t bind function in Render method

Some developer made a  mistake of binding  a function into render method like below.

React

The issue with the above pattern is that when we bind the function into render method it always provide a new instance or reference of the function of child component in each case of render. For example, in you have a parent component(Main.jsx) and you pass a function as a prop to child component and you bind this function into render method of the parent component, whenever the render method of parent component (main.jsx) is called,  it passes a new instance to the child component. Because child component gets the new reference of the prop so it will render also even though your child component is a Pure Component.  Let’s take an example to understand this issue.

Main.jsx

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3. import Child from '../child/child';    
  4. class Main extends React.Component {      
  5.     constructor(props) {    
  6.       super(props);            
  7.       this.state = {   
  8.         name:'Pankaj',  
  9.          city: "Alwar",  
  10.          data:[Date.now()]    
  11.       }  
  12.    }   
  13.   
  14.    addData(){  
  15.        var arrayData=this.state.data;  
  16.        arrayData.push(Date.now());  
  17.        this.setState({data:new Array(arrayData)});  
  18.    }  
  19.     alertMethod(data){  
  20.        console.log(data);  
  21.    }  
  22.    render() {    
  23.        console.log('Main Component render');    
  24.       return (    
  25.           <div>          
  26.          <p>User Name: {this.state.name}</p>    
  27.          <p>User City: {this.state.city}</p>  
  28.          <p>User Data: {this.state.data.join("  ,")}</p>   
  29.          <Child childProps={(e)=>this.alertMethod(e)} name="pankaj"></Child>  
  30.          <input type="button" value="UpdateData" onClick={this.addData.bind(this)} />   
  31.          </div>    
  32.       );      
  33.    }    
  34.        
  35. }      
  36.  export default Main;    

child.jsx

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3.     
  4. class Child extends React.PureComponent {      
  5.     constructor(props) {    
  6.       super(props);  
  7.       this.transferData=this.transferData.bind(this);  
  8.    }   
  9.       
  10.    transferData(e){  
  11.         this.props.childProps(e.target.value);  
  12.    }  
  13.    render() {    
  14.        console.log('Child Component render '+Date.now());    
  15.       return (    
  16.           <div>      
  17.           <input type="text" onChange ={this.transferData}/><br/>  
  18.           <input type="button" value="Child Button" onClick={this.props.childProps} />   
  19.          </div>    
  20.       );      
  21.    }    
  22.        
  23. }      
  24. Child.propTypes ={    
  25.     childProps:PropTypes.func.isRequired,    
  26.    }      
  27.       
  28. export default Child;    

When you click on the “UpdateData” method it will update the “main” component’s stat because a state changes and it will re-render the view and provide a new reference of the “alertMethod” to child component and as a result child component also re-renders.

React

To overcome this issue, we have to avoid the binding of function into render method.  Instead we have to bind the method in the constructor of a component. Let’s modify our main component and check the difference.

Main.jsx

  1. import React from 'react';      
  2. import PropTypes from 'prop-types';    
  3. import Child from '../child/child';    
  4. class Main extends React.Component {      
  5.     constructor(props) {    
  6.       super(props);            
  7.       this.state = {   
  8.         name:'Pankaj',  
  9.          city: "Alwar",  
  10.          data:[Date.now()]    
  11.       }  
  12.       this.alertMethod=this.alertMethod.bind(this);   
  13.    }   
  14.   
  15.    addData(){  
  16.        var arrayData=this.state.data;  
  17.        arrayData.push(Date.now());  
  18.        this.setState({data:new Array(arrayData)});  
  19.    }  
  20.     alertMethod(data){  
  21.        console.log(data);  
  22.    }  
  23.    render() {    
  24.        console.log('Main Component render');    
  25.       return (    
  26.           <div>          
  27.          <p>User Name: {this.state.name}</p>    
  28.          <p>User City: {this.state.city}</p>  
  29.          <p>User Data: {this.state.data.join("  ,")}</p>   
  30.          <Child childProps={this.alertMethod} name="pankaj"></Child>  
  31.          <input type="button" value="UpdateData" onClick={this.addData.bind(this)} />   
  32.          </div>    
  33.       );      
  34.    }    
  35.        
  36. }      
  37.  export default Main;    
React

As you can see, instead of binding into render method, we bind the function into the component section. So now, if we click on “UpdateData” method, it will not render the child component. Because now it will not provide the new instance of “alertMethod” every time.

React

Points to Notice about Pure Component

  • Use pure component instead of a simple component when you want to stop unnecessary re-rendering of the component.
  • Never bind the method or derive data into render method because it increases the re-rendering rate of child component.
  • A pure component can increase the performance of the application but use the pure component if you have really need it because extra and unnecessary use can degrade the application performance also.
  • Not only does pure component stop the re-rendering itself it also stops the re-rendering of child component. Also the best use of the pure component is when you don’t have any child component of pure component and don’t have any kind of dependency on the global state of the application.
  • A pure component will not render if you mutate the array of object that you are passing as props to a pure component from the parent component.

Conclusion

In this article, we learned what a pure component is, how it works, and what are the benefits of pure component. So, our final conclusion is that use of pure component can increase the performance of your application.  If you have any doubts and questions about this article then write in the comment section. Thanks for reading this article.