Before digging into the PureCompoment thoroughly let’s understand the difference between React component and PureComponent
NOTE: Considering you have basic knowledge of react.
In React Component, If you want to optimize performance then we have to implement shouldComponentUpdate lifecycle method where we can add condition check to see is props or state has been different from previous ones or not If it changed then only we will return true in shouldComponentUpdate method which will force to call render method otherwise render will get called every time props or state changed.
What PureComponent makes different from Component?
If you are extending the PureComponent class then you don’t need to take care of shouldComponentUpdate lifecycle method. PureComponent itself takes care by shallow checking states and props. If it finds states and props are different from the previous state and props then only it calls render method else not.
What does shallow check mean?
Shallow compare does check for equality. When comparing primitive values (numbers, strings) it compares their values. When comparing nonprimitive like objects or arrays, it does not compare their’s attributes – only their references are compared
For eg., If you have an array and you are pushing element to an existing array then PureComponent does not trigger render method because as per PureComponent there is no change happened because reference is still the same
Let’s go by example
import React, { PureComponent } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
class App extends PureComponent {
constructor() {
super();
this.state = {
personArr: [
{
name: "abc",
age: "22 years",
gender: "male"
},
{
name: "pqr",
age: "23 years",
gender: "female"
},
{
name: "mno",
age: "24 years",
gender: "male"
}
]
};
}
addPerson() {
var persons = this.state.personArr;
persons.push({
name: "xyz",
age: "32 years",
gender: "male"
});
this.setState({
perosnArr: persons
});
}
render() {
const persons = this.state.personArr.map((person, index) => {
return (
<section>
<div>
<label>Name:</label> {person.name}
</div>
<div>
<label>Age:</label>
{person.age}
</div>
<div>
<label>Gender:</label>
{person.gender}
</div>
</section>
);
});
return (
<div className="App">
<button onClick={() => this.addPerson()}>Add person</button>
{persons}
</div>
);
}
}
render(<App />, document.getElementById('root'));
As you can see in the above code we are rendering a person’s array and also we have added person button which pushing person object to an existing array.
so, Here PureComponent not let render method run because here an array is a non-primitive type so reference has been checked.
Here I think you might be thinking why PureComponent only checks the reference, not internal attributes because if react implements this logic then it’s going to be a very expensive operation performance-wise.
Still, you want to run the render method after pushing element to an array then you should not mutate existing array, even react suggest should not mutate existing element.
For eg.
addPerson(){
const perosnArr = this.state.personArr;
perosnArr.push({
name: "xyz",
age: "32 years",
gender: "male"
})
this.setState({
perosnArr: {...personArr}
})
}
As you can see above I am not mutating existing array, I have created a new array using spread operator now the reference is different for old and new array so now render method will trigger.
Please check the example here
Improve performance in functional components using React.memo()
React memo is a high order function that works the same as PureComponent. React memo is useful when functional react comes into the picture.
Because we can’t use PureComponent with functional components
for eg.
import React from 'react'
// with es5 functions
const techBoxWebComponent = react.memo(function(prop){
// only render when props changed
return <div>{prop.name}</div>
})
// can also be an es6 arrow function
const techBoxComp2= React.memo(props => {
return <div>my memoized component</div>;
});
// and even shorter with implicit return
const techBox3= React.memo(props => (
<div>implicit memoized component</div>
));
// also can wrap existing component
const techBoxExistingComponent = props => <div>my rocket component. {props.fuel}!</div>;
// createed a version that only renders on prop changes
const MemoizedRocketComponent = React.memo(techBoxExistingComponent);
Above we have covered react.memo possible examples
Conclusion:
When performance is a concern then PureComponent and react.memo always come for Rescue.