React.Component vs. React.PureComponent: Understanding Performance Optimization in React.js

2024-07-27

  • The fundamental class for creating components in React.js.
  • All components inherit from React.Component directly or indirectly.
  • Renders UI based on its props (external data passed down from parent components) and internal state (data managed by the component itself).
  • By default, React.Component re-renders whenever its props or state changes, regardless of whether the change actually affects the UI.

React.PureComponent (Performance Optimization)

  • A subclass of React.Component specifically designed for performance optimization.
  • Inherits all the functionality of React.Component.
  • Implements a built-in shouldComponentUpdate() method that performs a shallow comparison of the previous and current props and state.
  • Only re-renders the component if the comparison reveals a difference. This avoids unnecessary re-renders that don't impact the UI.

Choosing Between Them

  • Use React.Component for components with complex logic or frequent state updates where a shallow comparison might not be sufficient.
  • Use React.PureComponent for components where the rendering output is purely determined by the props and state, and you want to avoid unnecessary re-renders that could hinder performance.

Key Points:

  • React.PureComponent is generally preferred for performance optimization in most scenarios.
  • Be mindful of potential issues with shallow comparison:
    • If props or state contain nested objects or arrays, changes within them might not be detected unless you implement deeper comparisons manually.
    • Consider using libraries like immutability-helper to create immutable updates to objects and arrays, which can trigger re-renders in React.PureComponent.
  • React recommends using functional components with hooks (useState, useEffect) as the primary way to create components in modern React development. These components are inherently more performant and easier to reason about.



import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    const { count } = this.state;

    // Simulate some expensive calculation (not related to rendering)
    for (let i = 0; i < 1000000; i++) {
      // Do some work...
    }

    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

export default Counter;

In this example, Counter is a basic component that manages its own count state. Clicking the button increments the count, but the expensive calculation in render (not related to the UI) will cause a re-render on every click, even though it doesn't affect the displayed count. This can be inefficient.

import React, { PureComponent } from 'react';

class PureCounter extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    const { count } = this.state;

    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

export default PureCounter;

Here, PureCounter inherits from React.PureComponent. Now, the shallow comparison in shouldComponentUpdate will prevent unnecessary re-renders if only the expensive calculation changes. This improves performance in cases where the UI doesn't rely on the calculation outcome.




  • The recommended approach in modern React.
  • Functional components are simpler to write and reason about compared to class-based components.
  • Hooks like useState manage component state, and useEffect handles side effects or subscriptions.
  • By default, React performs a shallow comparison of props passed to functional components, leading to similar optimization benefits as React.PureComponent.

Example:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

export default Counter;

Memoization with React.memo:

  • A higher-order component (HOC) for performance optimization.
  • Wraps a component and compares its props on each render.
  • If the props haven't changed, it skips re-rendering the wrapped component, improving performance.
import React, { memo } from 'react';

const ExpensiveComponent = ({ data }) => {
  // Simulate expensive rendering
  console.log('Expensive component rendered');
  return <div>Data: {JSON.stringify(data)}</div>;
};

const MemoizedExpensiveComponent = memo(ExpensiveComponent);

export default MemoizedExpensiveComponent;

Custom shouldComponentUpdate (For Complex Scenarios):

  • If functional components with hooks or React.memo don't suffice, you can define a custom shouldComponentUpdate method.
  • This method allows for more granular control over re-renders based on specific prop and state comparisons.

Remember:

  • Use React.Component or React.PureComponent sparingly in new React projects.
  • Functional components with hooks are generally preferred for most use cases.
  • Consider React.memo for performance optimization of components that are expensive to render and only rely on props for their output.
  • For very complex scenarios, implement a custom shouldComponentUpdate method cautiously, as it can add complexity.

reactjs state



Understanding React JSX: Selecting "selected" on a Selected <select> Option

Understanding the <select> Element:The <select> element in HTML represents a dropdown list.It contains one or more <option> elements...


Understanding Virtual DOM: The Secret Behind React's Performance

Imagine the Virtual DOM (VDOM) as a lightweight, in-memory copy of your React application's actual DOM (Document Object Model). It's a tree-like structure that mirrors the elements on your web page...


Keeping Your React Components Clean: Conditional Rendering and DRY Principles

ReactJS provides several ways to conditionally render elements based on certain conditions. Here are the common approaches:...


Understanding Parent-Child Communication in React: The Power of Props

Here's a breakdown of the process:Parent Component:Define the data you want to pass as props within the parent component...


React: Why You Can't Use 'for' Attribute Directly on Label Elements

In JavaScript, for is a reserved keyword used for loop constructs.When you directly use for as an attribute in JSX (React's syntax for creating HTML-like elements), it conflicts with this keyword's meaning...



reactjs state

Understanding the Code for Rerendering React Views on Resize

Concept:In React, components are typically rendered once when they're first mounted to the DOM.However, in certain scenarios


Accessing Custom Attributes from Event Handlers in React

React allows you to define custom attributes on HTML elements using the data-* prefix. These attributes are not part of the standard HTML specification and are used to store application-specific data


Unveiling the Secrets of React's Performance: How Virtual DOM Beats Dirty Checking

Directly updating the DOM (Document Object Model) in JavaScript can be slow. The DOM represents the structure of your web page


Communicating Between React Components: Essential Techniques

React applications are built from independent, reusable components. To create a cohesive user experience, these components often need to exchange data or trigger actions in each other


Unlocking Dynamic Content in React: Including Props Within JSX Quotes

In React, components can receive data from parent components through properties called props.These props allow you to customize the behavior and appearance of child components