Learn React Now
  • Table of Content
  • Design Patterns and Techniques
    • Conditional in JSX
    • Async Nature Of setState()
    • Dependency Injection
    • Context Wrapper
    • Event Handlers
    • Flux Pattern
    • One Way Data Flow
    • Presentational vs Container
    • Third Party Integration
    • Passing Function To setState()
    • Decorators
    • Feature Flags
    • Component Switch
    • Reaching Into A Component
    • List Components
    • Format Text via Component
    • Share Tracking Logic
  • Anti-patterns
    • Introduction
    • Props In Initial State
    • findDOMNode()
    • Mixins
    • setState() in componentWillMount()
    • Mutating State
    • Using Indexes as Key
    • Spreading Props on DOM elements
  • Coding Styles
  • Handling UX Variations
    • Introduction
    • Composing UX Variations
    • Toggle UI Elements
    • HOC for Feature Toggles
    • HOC props proxy
    • Wrapper Components
    • Display Order Variations
  • Performance Tips
    • Introduction
    • shouldComponentUpdate() check
    • Using Pure Components
    • Using reselect
  • Styling
    • Introduction
    • Stateless UI Components
    • Styles Module
    • Style Functions
    • npm Modules
    • Base Component
    • Layout Component
    • Typography Component
    • HOC for Styling
  • Gotchas
    • Introduction
    • Pure render checks
    • Synthetic Events
    • Related Links
Powered by GitBook
On this page
  • Case 1
  • Case 2
  • Related links:

Was this helpful?

  1. Gotchas

Pure render checks

In order to preserve performance one needs to consider the creation of new entities in the render method.

Pure render?

With React.js pure render I am talking about components that implement the shouldComponentUpdate method with shallow equality checks.

Examples of this are the React.PureComponent, PureRenderMixin, recompose/pure and many others.

Case 1

The bad way

class Table extends PureComponent {
  render() {
    return (
      <div>
        {this.props.items.map(i =>
          <Cell data={i} options={this.props.options || []}/>
        )}
      </div>
    );
  }
}

The issue is with {this.props.options || []} - it cause all the cells to be re-rendered even for a single cell change. Why?

You see the options array was passed deep down in the Cell elements. Normally this would not be an issue. The other Cell elements would not be re-rendered because they can do the cheap shallow equality check and skip the render entirely but in this case the options prop was null and the default array was used.

As you should know the array literal is the same as new Array() which creates a new array instance. This completely destroyed every pure render optimization inside the Cell elements. In Javascript different instances have different identities and thus the shallow equality check always produces false and tells React to re-render the components.

The good way

const defaultval = [];  // <---  The fix (defaultProps could also have been used).
class Table extends PureComponent {
  render() {
    return (
      <div>
        {this.props.items.map(i =>
          <Cell data={i} options={this.props.options || defaultval}/>
        )}
      </div>
    );
  }
}

Case 2

Similar issue with using functions in render() as well

The bad way

class App extends PureComponent {
  render() {
    return <MyInput
      onChange={e => this.props.update(e.target.value)}/>;
  }
}

Another bad way

class App extends PureComponent {
  update(e) {
    this.props.update(e.target.value);
  }

  render() {
    return <MyInput onChange={this.update.bind(this)}/>;
  }
}

In both above cases, a new function is created with a new identity. Just like with the array literal. We need to bind the function early.

The good way

class App extends PureComponent {
  constructor(props) {
    super(props);
    this.update = this.update.bind(this);
  }

  update(e) {
    this.props.update(e.target.value);
  }

  render() {
    return <MyInput onChange={this.update}/>;
  }
}

The bad way

class Component extends React.Component {
  state = {clicked: false};

  onClick() {
    this.setState({clicked: true})
  }

  render() {
    // Options object created each render if not set
    const options = this.props.options || {test: 1};

    return <Something
      options={options}
      // New function created each render
      onClick={this.onClick.bind(this)}
      // New function & closure created each render
      onTouchTap={(event) => this.onClick(event)
    />
  }
}

The good way

class Component extends React.Component {
  state = {clicked: false};
  options = {test: 1};

  onClick = () => {
    this.setState({clicked: true})
  };

  render() {
    // Options object created once
    const options = this.props.options || this.options;

    return <Something
      options={options}
      onClick={this.onClick} // Function created once, bound once
      onTouchTap={this.onClick} // Function created once, bound once
    />
  }
}

Related links:

  • https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f

  • https://github.com/nfour/js-structures/blob/master/guides/react-anti-patterns.md#pure-render-immutability

  • Optimizing React Rendering

PreviousIntroductionNextSynthetic Events

Last updated 4 years ago

Was this helpful?