Analysis: how and why to apply PureComponent in React


    React 15.3 came out on July 29th, and the first item in release-notes was adding support for React.PureComponent, which replaces its predecessor, pure-render-mixin. This article will discuss why this component is so important and where to use it.

    This is one of the most significant ways to optimize react applications, which can be implemented quite easily and quickly. Using pure-render-mixin gives a noticeable increase in performance, as the number of renders in the application is reduced, which means that react, in turn, performs much less operations.

    image

    PureComponent modifies the shouldComponentUpdate lifecycle method, automatically checking whether the component needs to be redrawn. At the same time, PureComponent will call the render only if it detects changes in state or props of the component, which means that in many components you can change state without having to constantly write

    if (this.state.someVal !== computedVal) {
        this.setState({someVal: computedVal})
    }
    

    In the React sources, provided that the component is “Pure”, and the following check is performed:

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

    Using shallowEqual suggests that there is a shallow check of params and state, so that the comparison will not occur on deeply nested objects, arrays.

    Deep comparison is a very expensive operation. If PureComponent caused it every time, then it would do more harm than good. No one bothers to use the proven shouldComponentUpdate to manually determine the need for a new render. The easiest option is a direct comparison of the parameters.

    shouldComponentUpdate(nextProps, nextState) { 
        return nextProps.user.id === props.user.id; 
    }

    You can also use immutable data. Comparison in this case becomes very simple, since the available variables are not changed, but new ones are always created. Libraries like Immutable.js are our loyal ally.

    Application features


    PureComponent saves us time and allows us not to write extra code, but it is not a panacea. It is important to know the features of its application, otherwise utility is lost. Since PureComponent involves shallow validation, changes to its props and state may remain ignored. For example, the parent component has a render and a click handler:

      handleClick() {
        const items = this.state.items;
        items.push('new-item');
        this.setState({items: items});
      }
      render() {
        return (
          
    ); }

    If the ItemList component is PureComponent, then when items are changed after clicking the button, nothing will happen. This happens because this.state.items will be equal to the old version of this.state.items when comparing, although its contents have changed. However, this can be easily fixed by removing mutations, for example like this:

    handleClick() {
      this.setState(prevState => ({
        words: prevState.items.concat(['new-item'])
      }));
    }
    

    PureComponent will always redraw components if it receives links to different objects. This means that if we do not want to lose the benefits of PureComponent, such constructions should be avoided:


    A new array, although empty, will always force the component to be redrawn.
    To avoid this is very simple, for example, using DefaultProps, in which you can set the initially empty state of the transmitted variable. You can also often see the following components:

    this.props.update (e.target.value)} />;
    When they are created, a new function will always be created, which means that PureComponent will see new data every time. This is treated, for example, with the bind of the desired function in the component constructor.

    constructor(props) {
        super(props); this.update = this.update.bind(this); 
    }
    update(e) {
        this.props.update(e.target.value); 
    } 
    render() { 
        return ; 
    }
    

    Also, any component that contains children created in JSX will always return false on shallowequal checks.

    It is important to remember that PureComonent skips rendering not only the component itself, but also all of its “children”, so it’s safest to use it in presentational components, without “children” and without depending on the global state of the application.

    What is the result


    In fact, switching to PureComponent is quite simple, if you know a number of features related more to JS itself than to React. In many components, I replaced:

    class MyComponent extends Component {…}
    

    on the:

    class MyComponent extends PureComponent {…} 
    

    ... and they continued to work quietly, and even with increased productivity.

    So try and use, the component is very useful.

    EDIT
    Thanks raveclassic for a helpful comment. If the pure component has children, all child components depending on a context change will not respond to changes if contextTypes is not declared in the parent pure component.

    Also popular now: