Why?

React15.3 added a new PureComponent class. Pure stands for pure component. Replacing its predecessor PureRenderMixin,PureComponent is one of the most important ways to optimize React applications. It’s easy to implement by changing the inherited class from Component to PureComponent. You can improve performance by reducing the number of unnecessary render operations, and you can save some code by writing shouldComponentUpdate less.

The principle of

When the component is updated, if the props and state of the component are not changed, the render method will not trigger, saving the Virtual DOM generation and comparison process to improve performance. React automatically provides a shallow comparison:

if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = ! shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState); }Copy the code

And what does shallowEqual do? Will be Object. Keys (the state | props) whether the length of the agreement, each key for both, and whether it is a reference, is the only compares the value of the first layer is very shallow, so deeply nested data as compared to not to come out.

Use guide

Volatile data cannot use a reference

Case study:

class App extends PureComponent {
  state = {
    items: [1, 2, 3]
  }
  handleClick = () => {
    const { items } = this.state;
    items.pop();
    this.setState({ items });
  }
  render() {
    return (< div>
      < ul>
        {this.state.items.map(i => < li key={i}>{i}< /li>)}
      < /ul>
      < button onClick={this.handleClick}>delete< /button>
    < /div>)
  }
}
Copy the code

You can see that no matter how much you hit the delete button, li is not going to get less, because you’re using a reference, and shallowEqual is going to be true. Fix it:

handleClick = () => {
  const { items } = this.state;
  items.pop();
  this.setState({ items: [].concat(items) });
}
Copy the code

Each change will generate a new array and render it. There is a contradiction here if there is no items.pop(); Operation, each time the items data does not change, but still render, isn’t it very fucked up? Why do you setState when data doesn’t change?

Invariant data uses a reference

Function attributes

When passing a function to a component, we sometimes like:

< MyInput onChange={e => this.props. Update (e.targe.value)} /> // or update(e) {this.props. 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. It’s better to write:

update = (e) => {
  this.props.update(e.target.value)
}
render() {
  return < MyInput onChange={this.update} />
}Copy the code

An empty object or array

If the array length is 0 or the object has no properties, a null is returned in the background. In this case, we need to do some fault tolerance:

class App extends PureComponent {
  state = {
    items: [{ name: 'test1' }, null, { name: 'test3'  }]
  }
  store = (id, value) => {
    const { items } = this.state;
    items[id]  = assign({}, items[id], { name: value });
    this.setState({ items: [].concat(items) });
  }
  render() {
    return (< div>
      < ul>
        {this.state.items.map((i, k) =>
          < Item store={this.store} key={k} id={k} data={i || {}} />)
        }
      < /ul>
    < /div>)
  }
}
Copy the code

When a subcomponent calls the store function to change its property and trigger the render operation, the data property is a {} each time if the data is null, {} ==== {} is false, which renders the subcomponents unnaturally.

It is best to set defaultValue to {} as follows:

defaultValue = {}
< Item store={this.store} key={k} id={k} data={i || defaultValue} />Copy the code

Complex and simple states do not share a component

This may not have much to do with PureComponent, but doing it badly can waste a lot of performance, such as a page with a complex list at the top and an input box below, abstracting code:

change = (e) => { this.setState({ value: e.target.value }); } render() { return (< div> < ul> {this.state.items.map((i, k) => < li key={k}> {... }< /li>)} < /ul> < input value={this.state.value} onChange={this.change} /> < /div>) }Copy the code

There is no connection between the form and the list, and the value of the form may change frequently, but it does not need to diff the list. It is better to extract the list into a separate PureComponent, so that the state.items remain unchanged. The list will not be rerendered.

withshouldComponentUpdatecoexistence

If PureComponent has a shouldComponentUpdate function, use the result of the shouldComponentUpdate function as the update basis. If PureComponent has a shouldComponentUpdate function, use the result as the update basis. If it is a PureComponent, shallowEqual comparison will be performed.

Var shouldUpdate = true; / / inst is component instance if (inst. ShouldComponentUpdate) {shouldUpdate = inst. ShouldComponentUpdate (nextProps nextState, nextContext); } else { if (this._compositeType === CompositeType.PureClass) { shouldUpdate = ! shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState); }}Copy the code

Older versions are compatible

import React { PureComponent, Component } from 'react';
class Foo extends (PureComponent || Component) {
  //...
}Copy the code

This won’t die in older versions of React.

conclusion

PureComponent is only really useful on presentation components. Complex components don’t need to pass shallowEqual, but props and state can’t use the same reference.

WeChat exceptional

Alipay rewards


Did this article help you? Welcome to join the front End learning Group wechat group: