Frontend Development 13 min read

Improving React Performance: Reducing Unnecessary Renders

This article explains how React's virtual DOM and diff algorithm work, identifies situations where renders become costly, and presents practical techniques such as shouldComponentUpdate, PureComponent, higher‑order components, React.memo, and component splitting to reduce unnecessary renders and improve front‑end performance.

政采云技术
政采云技术
政采云技术
Improving React Performance: Reducing Unnecessary Renders

Performance and Rendering are Correlated

React uses a virtual DOM and an efficient diff algorithm to update the real DOM with minimal changes. In most cases this rendering performance is sufficient, but in complex business scenarios unnecessary renders can still cause performance problems, so avoiding them becomes essential.

Points that Affect Performance During Render

React's basic model re‑renders the whole application whenever there is a change. Before the virtual DOM era the simplest approach was to call innerHTML directly. The power of the virtual DOM is not that it is faster than direct DOM manipulation, but that it updates the DOM with the smallest possible cost regardless of how the data changes. React compares the new virtual DOM tree returned by the render function with the previous one to decide whether and how to update the real DOM. When the DOM tree is large, traversing and diffing both trees is costly, especially when a tiny change at the top level triggers a full‑tree traversal. Even though React uses a highly optimized diff algorithm, this process still consumes performance.

When Render Is Triggered

Component Mounting

Mounting is the process of constructing a React component and inserting its DOM elements into the page. The first render occurs automatically during mounting.

Calling setState()

In most cases calling setState triggers a render, but not always. If setState is called with null , React will not re‑render. The following demo illustrates this behavior:

class App extends React.Component {
  state = { a: 1 };
  render() {
    console.log("render");
    return (
{this.state.a}
{ this.setState({ a: 1 }); }}>Click me
this.setState(null)}>setState null
);
  }
}

Parent Component Re‑rendering

When a parent component re‑renders, its child components also re‑render even if the props passed to the child have not changed.

const Child = () => {
  console.log("child render");
  return
child
;
};

class App extends React.Component {
  state = { a: 1 };
  render() {
    console.log("render");
    return (
{this.state.a}
{ this.setState({ a: 1 }); }}>Click me
this.setState(null)}>setState null
);
  }
}

How to Optimize Render

Unnecessary renders lead to performance degradation, especially when there are many child components or deep component hierarchies. The primary optimization goal is to reduce such renders.

shouldComponentUpdate and PureComponent

In class components you can use shouldComponentUpdate or extend PureComponent to prevent child renders caused by parent updates. Returning false from shouldComponentUpdate skips the render.

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

PureComponent performs a shallow comparison of props and state. For deeply nested objects this may miss changes, because shallow equality does not detect modifications inside nested structures.

const hasOwnProperty = Object.prototype.hasOwnProperty;

function is(x, y) {
  if (x === y) {
    return x !== 0 || y !== 0 || 1 / x === 1 / y;
  } else {
    return x !== x && y !== y;
  }
}

function shallowEqual(objA, objB) {
  if (is(objA, objB)) return true;
  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) return false;
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  if (keysA.length !== keysB.length) return false;
  for (let i = 0; i < keysA.length; i++) {
    if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
      return false;
    }
  }
  return true;
}

Higher‑Order Components (HOC)

Function components lack shouldComponentUpdate , but you can create an HOC that provides similar behavior.

const shouldComponentUpdate = arePropsEqual => BaseComponent => {
  class ShouldComponentUpdate extends React.Component {
    shouldComponentUpdate(nextProps) {
      return arePropsEqual(this.props, nextProps);
    }
    render() {
      return
;
    }
  }
  ShouldComponentUpdate.displayName = `Pure(${BaseComponent.displayName})`;
  return ShouldComponentUpdate;
};

const Pure = BaseComponent => {
  const hoc = shouldComponentUpdate((props, nextProps) => !shallowEqual(props, nextProps));
  return hoc(BaseComponent);
};

Wrap a functional component with Pure to give it the same optimization.

import React from 'react';

const Child = props =>
{props.name}
;
export default Pure(Child);

React.memo

React.memo (introduced in React 16.6) caches the result of a functional component, preventing unnecessary renders. It works similarly to PureComponent but only for function components.

Basic usage

import { memo } from 'react';
function Button(props) {
  // component code
}
export default memo(Button);

Advanced usage

By default memo performs a shallow prop comparison. For complex objects you can provide a custom comparison function as the second argument.

function arePropsEqual(prevProps, nextProps) {
  // your custom comparison logic
  return prevProps === nextProps;
}
export default memo(Button, arePropsEqual);

Reasonable Component Splitting

Just as micro‑services split a monolithic application into smaller, independently deployable units, splitting a large UI into smaller components reduces the granularity of renders and improves performance.

Summary

This article introduced methods to reduce unnecessary render calls in React, thereby improving performance. While front‑end performance issues may not be common in simple applications, they become increasingly likely as business complexity grows.

Reduce render frequency: class components can use shouldComponentUpdate or PureComponent ; function components can use higher‑order components or React.memo .

Split components sensibly to limit render scope.

frontendPerformanceJavaScriptReactReact.memorender optimization
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.