PureComponent introduction
React PureRenderMixin is a rewrite of the React shouldComponentUpdate method to optimize React performance. But since React15.3 added a new PureComponent class that makes it easy to use in your own components, you can simply replace Component with PureComponent, so the authors recommend using today’s PureComponent.
PureComponent principle
We know that a change in the component’s state and props will trigger render, but if the component’s state and props are not changed, the render will not execute, and only if PureComponent detects a change in the state or props, PureComponent calls the Render method, so you can improve performance without having to write extra checks manually. React actually makes the outermost shallow comparison:
if(this._compositeType === CompositeTypes.PureClass) { shouldUpdate = ! shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState); }Copy the code
ShadowEqual checks only the props and state of the component, so nested objects and arrays are not compared. A deep comparison is a time consuming operation that iterates through the key values of the enumeration level by level. If comparing deep cases, you can also use shouldComponentUpdate to manually compare individual cases to see if they need to be rerendered. The easiest way to do this is to compare props or state directly:
shouldComponentUpdate(nextProps, nextState) {
return nextProps.xxx.xx === props.xxx.xx;
}
Copy the code
In addition, you can use the immutable property, immutable. Js is an immutable library. In this case, attribute comparison is very easy because existing objects are not changed and new objects are created instead.
Using PureComponent
Pit crawl 1: Volatile data cannot be used with a reference
PureComponent saves us time and unnecessary code. Well, it’s very important to know how to use it properly, otherwise it won’t work if it’s not used properly. For example, let’s consider a case where the parent component has a Render method and a click handler:
handleClick() {
let {items} = this.state
items.push('new-item')
this.setState({ items })
}
render() {
return (
<div>
<button onClick={this.handleClick} />
<ItemList items={this.state.items} />
</div>
)
}
Copy the code
Since ItemList is a pure component, clicking on it won’t render, but we did add a new value to this.state.items, but it still points to a reference to the same object. However, this can easily be changed by removing mutable objects so that they are rendered correctly.
handleClick() {
this.setState(prevState => ({
words: prevState.items.concat(['new-item'])}}))Copy the code
Pit crawl 2: Invariant data using a reference
The above mutable data cannot be used in a reference case where there is a click delete operation, if we delete the code like this:
constructor(props){
super(props)
this.state={
items: [{a: 1}, {a: 2}, {a: 3}]
}
}
handleClick = () => {
const { items } = this.state;
items.splice(items.length - 1, 1);
this.setState({ items });
}
Copy the code
Items references are also changed, but state.items[0] === nextState.items[0] is false if items contain reference type data, and the child components are still re-rendered. This requires us to ensure that references to immutable child component data cannot be changed. In this case, we can use the imMUTABLE js library.
Pit crawl 3: The parent passes the callback function to the child via props
When we pass the callback function in parent-child communication:
// step1
<MyInput onChange={e => this.props.update(e.target.value)} />
// step2
update(e) {
this.props.update(e.target.value)
}
render() {
return <MyInput onChange={this.update.bind(this)} />
}
Copy the code
Since each render operation on MyInput’s onChange property returns a new function, the parent component’s render also causes MyInput’s render, even if it hasn’t changed anything, so avoid this. Best package:
update = (e) => {
this.props.update(e.target.value)
}
render() {
return <MyInput onChange={this.update} />
}
Copy the code
Pit crawl 4: New arrays, empty arrays, will also cause components to be re-rendered
<Entity values={this.props.values || []}/>
Copy the code
To avoid this problem, you can use defaultProps, which contains an initialized null state for the property. When a PureComponent is created, it gets new data and rerenders because the function’s new object is created. The easiest way to solve this problem is to use bind in the component’s constructor method.
constructor(props) {
super(props)
this.update = this.update.bind(this)
}
update(e) {
this.props.update(e.target.value)
}
render() {
return <MyInput onChange={this.update} />
}
Copy the code
Also, in JSX, shallowEqual checks always return false for any component that contains child elements.
PureComponent usage
The usage is simple:
import React { PureComponent, Component } from 'react';
class Foo extends (PureComponent || Component) {
//...
}
Copy the code
React is compatible with older versions of React.
conclusion
1. Ignoring rerendering of pure components affects not only the component itself but also its child elements, so the best case for using PureComponent is to present components that have neither child components nor depend on the global state of the application
ShallowEqual is not going to pass, but you can’t use the same reference for props and state.