20

Pure Components in React

 5 years ago
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.set1newSet1 , 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:

https://reactjs.org/docs/react-api.html#reactpurecomponent

https://facebook.github.io/immutable-js/docs/#/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK