Pure Components in React
source link: https://www.tuicool.com/articles/hit/za2Y7vi
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Pure components were introduced in React 15.3. React.Component
and React.PureComponent
differ in implementing the shouldComponentUpdate()
lifecycle method. The shouldComponentUpdate()
method
decides the re-rendering of the component by returning a boolean. In React.Component
, it returns true by default. But in pure components, shouldComponentUpdate()
compares if there are any changes in state or props to re-render the component.
Here I am sharing my observations about how unnecessary renders are reduced by the pure component.
import React from 'react'; class Car extends React.Component{ state={type:"Xylo"} changeType = () => { this.setState({ type:"Xylo"}) } render(){ console.log("Car -- Render"); return (<div>Car <button onClick={this.changeType}>Change Type</button> </div>) } } export default Car;
Here, render()
will be called for each set State()
,
though we are not representing the “type” property in the JSX and also the “type” property is not changing. We need to stop calling render()
in both the above situations. To make this happen, shouldComponentUpdate()
should
return true by:
- comparing only the properties represented in the JSX. Here, the “type” property is not represented in the JSX. It is unnecessary to re-render the Car component.
- checking if the properties are really changing, i.e. is the “type” property really changing?
Pure components come into the picture in the second scenario. Pure components compare all the properties of the current state with the next state, and current props with next props for every set state()
call of itself or its parent in the hierarchy. Thus, it helps in reducing unnecessary render()
method calls.
A very specific thing about pure components is the shallow comparison. JavaScript is completely based on objects. The comparison is based on address references. In a shallow comparison, the references of the objects are compared leaving the internal references in the object uncompared. This creates a problem while working with objects with mutable nested structures along with pure components.
Pure Components Used With Mutable Objects
Mutable objects share the same reference. A change in one would affect the other object. So, updating them would result in mutating the state directly due to a shallow comparison. This is not a good approach. Let’s look at an example:
class Courses extends React.PureComponent{ state={ arr:[{id:1,name:"C"},{id:2,name:"C++"},{id:3,name:"Java"}] } changeArr = () => { let arr1 = [...this.state.arr]; arr1[1].name = "Javascript"; console.log(arr1[1] === this.state.arr[1]); this.setState({arr:arr1}, ()=>{ console.log("Done ",this.state.arr); }); } }
Here, this.state.arr
and
arr1
share a different reference. But their internal structures still share the same references. As a result, a change in arr1
would change the this.state.arr
. Looks like the state is updated but the state is mutated. Because arr1[1] === this.state.arr[1]
is true. A shallow comparison results in updates to the virtual DOM, but the state is also mutated. If nested mutable objects need to be used with pure components, then we need to either:
-
use
forceUpdate()
for updating state manually. - use the Immutable.js library to create immutable data for nested mutable structures.
forceUpdate( )
This method reads the latest state, props, and non-state properties of the parent that are passed to the child. Its use is suited for small applications with minimal properties so that we can assume the scenarios and use them appropriately. This approach is not recommended.
Immutable.js
Immutable.js helps in creating immutable data structures for nested data. It always returns a new object with the updated operation. Therefore, it maintains immutability. It also helps in using map()
on the structures but the index cannot be accessed. Supported data structures include: List, Stack, Map, Ordered Map, Set, Ordered Set. and Record.
const { Set } = require('immutable'); p = 6; state = { set1:Set([1,2,3,4,5]) }; increment = () => { this.setState((oldState) => { let newSet1 = oldState.set1.add(this.p); this.p++; return {set1:newSet1} }) }
Here, the add()
operation does not add the element to the set1
. It creates a copy of this.state.set1
, adds the element p
, and returns the new object reference to newSet1
. Therefore, neither this.state.set1
, newSet1
,
nor the internal structures of these components share the same references. This implies that immutability has been maintained.
Conclusion
Pure components are ideal for classes with minimal and immutable properties. If we must use them with objects nested with mutable objects, it would be very complicated to maintain immutability. Irefer using Immutable.js in such scenarios.
References:
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK