React.componentdiffers from react.pureComponent in one way

PureComponent is basically the same as Component, except that it gives you a shouldComponentUpdate method with shallow comparisons. When props or state changes, the PureComponent makes a shallow comparison between props and state. Component, on the other hand, does not compare the props and state of the current and the next state. Therefore, whenever shouldComponentUpdate is called, the component is rerendered by default.

Light is 101

When comparing the props and state of the previous and the next, a shallow comparison checks to see if the original value has the same value (e.g. 1 == 1 or ture==true) and if the array and object references are the same.

Never change

You’ve probably heard that don’t change objects and arrays in props and state, and if you change objects in your parent component, your “pure” child component will not update. Although the value has been changed, the child component compares references to the previous props to see if they are the same, so no difference is detected.

Therefore, you can force a new object to be returned by using ES6’s Assign method or the array extension operator, or by using a third-party library.

Performance problems?

Comparing a raw value to an object reference is a low cost time operation. If you have a list of child objects and one of them is updated, it is much faster to check their props and state than to re-render each child node.

PureComponent solution

Do not bind values in render’s functions

Suppose you have a list of items, each of which passes a unique parameter to the parent method. To bind parameters, you might do the following:

<CommentItem likeComment={() => this.likeComment(user.id)} />

This problem causes a new function to be created every time the parent render method is called that has been passed into likeComment. This has the side effect of changing the props of each child component, which will cause them all to be re-rendered, even if the data itself has not changed.

To solve this problem, just pass a reference to the parent component’s prototype method to the child component. The likeComment property of the child component will always have the same reference, so there will be no unnecessary re-rendering.

<CommentItem likeComment={this.likeComment} userID={user.id} />

Then create a class method in the child component that references the passed property:

class CommentItem extends PureComponent {
  ...
  handleLike() {
    this.props.likeComment(this.props.userID)
  }
  ...
}
Copy the code

Do not derive data in the Render method

Consider that your configuration component presents ten of your users’ favorite articles from a list of articles.

render() {
  const { posts } = this.props
  const topTen = posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
  return/ /... }Copy the code

TopTen will have a new reference every time the component is re-rendered, even though the posts have not changed and the derived data is the same. This will cause unnecessary re-rendering of the list.

You can solve this problem by caching your derived data. For example, set derived data in your component state so that it is updated only when posts is updated.

componentWillMount() {
  this.setTopTenPosts(this.props.posts)
}
componentWillReceiveProps(nextProps) {
  if(this.props.posts ! == nextProps.posts) { this.setTopTenPosts(nextProps) } }setTopTenPosts(posts) {
  this.setState({
    topTen: posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
  })
}
Copy the code

If you are using Redux, consider using ResELECT to create “selectors” to combine and cache derived data.

Case analysis

Here we create the Greeting component, where we update the status title every 2 seconds with setInterval, and then call the clearInterval method after 6 seconds to cancel the ticker.

import React, {Component,Fragment} from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class Title extends React.Component {
  render() {
      console.log('rendering tut title ... ');
    return (
      <div>
        <span>{this.props.name}</span>
      </div>
    )
  }
}
class Subtitle extends React.Component {
  render() {
      console.log('rendering sub tittle... ')
    return (
        <div>
        <span>{this.props.name}</span>
      </div>
    )
  }
}
class Content extends  React.PureComponent {
  render() {
      console.log('rendering content ... ');
    return (
      <div>
        <span>{this.props.name.join(', ')}</span>
      </div>
    )
  }
}
export default class Greeting extends React.Component {
  constructor(props){
      super(props);
      this.state = {
          title:Math.random(),
          subTitle:Math.random(),
          content:['hello'].}}componentDidMount(){
      const id = setInterval(() => this.setState({title: Math.random()}),2000);
      setTimeout(()=> clearInterval(id),6000);  
  }
  render() {
    return (
      <Fragment>
        <Title name={this.state.title}/>
        <Subtitle name={this.state.subTitle}/>
        <Content name={this.state.content}></Content>
      </Fragment>
    )
  }
}


ReactDOM.render(
  <Greeting />,
  document.getElementById('root'));Copy the code

As you can see from the result, the value per second only updates the title value of the state, so you should only render the Subtitle, but also the Subtitle and Content, which we don’t want.

rendering tut title ...
rendering sub tittle...
rendering content ...
rendering tut title ...
rendering sub tittle...
rendering content ...
rendering tut title ...
rendering sub tittle...
rendering content ...
rendering tut title ...
rendering sub tittle...
rendering content ...
Copy the code

So we can use react. PureComponent or shouldComponentUpdate in the TutSubtitle, Content child for shallow comparisons to prevent unnecessary rendering of the child.

PureComponent {// Use react. PureComponent or shouldComponentUpdate, but not both. // shouldComponentUpdate(nextProps, nextState, nextContext) {// console.log(nextProps,nextState, this.props) //returnnextProps.name ! == this.props.name; / /}render() {
      console.log('rendering sub tittle... ')
    return (
        <div>
        <span>{this.props.name}</span>
      </div>
    )
  }
}
class Content extends  React.PureComponent {
  render() {
      console.log('rendering content ... ');
    return (
      <div>
        <span>{this.props.name.join(', ')}</span>
      </div>
    )
  }
}
Copy the code

Update the title state and render only the title component, which is exactly what we expect. Output:

rendering tut title ...
rendering sub tittle...
rendering content ...
3 rendering tut title ...
Copy the code

conclusion

This means that PureCompoent will perform better than Component. The following conditions must be met to use PureCompoent:

  1. Both props and state must be immutable objects.
  2. Props and state cannot have hierarchically nested structures (otherwise changes to subhierarchies will not be reflected in a shallow copy).
  3. If data changes are not reflected in the shallow copy, forceUpdate should be called to update the Component.
  4. Children of a PureComponent should also be pureComponents.

Refer to the article

When to use Component or PureComponent? React PureComponent vs. Component React PureComponent vs. Component