Why Does React Components Re-Render

Marcus Osterberg
3 min readFeb 5, 2019

--

This article is meant to be an easy to digest note to myself and fellow developers on good practices for how to avoid pointless re-renders.

Before we look into different APIs and techniques one needs to have a brief understanding about what re-renders are and how they can be problematic.

React achieves a fast and responsive UI by re-rendering components on every state change (using setState) or from changes of props, followed by React’s reconciliation diffing algorithm that diffs previous renders with current render output to determine if React should commit changes to the component tree (e.g. DOM) with the new updates.

However, unnecessary component re-renders will happen and can be expensive, It’s been a common performance pitfall in every single React project that I’ve been working on.

Alright, let’s move on.

Pure Components

Pure Components shallowly compares the old state & props with the new state & props. Always extend class components from React.PureComponent.

See example here

If you are like me and prefer the functional paradigm of React then use the memo wrapper to protect functional components from re-rendering given the same input.

See example here

Should Component Update

Most likely Pure Components will be sufficient enough. However in cases of props or state structures with deeply nested objects, values won’t be compared and you are better off using the shouldComponentUpdate life-cycle method which is invoked on state or prop changes before render is called. Use this mechanism for granular control over when a component should re-render.

See example here

Inline Functions

Passing anonymous functions as props will cause the receiving component to re-render every time its parent re-renders because anonymous functions are re-initialized on every state or props change. Even if the function is still the same it will create a new memory reference since the function has to be re-allocated. Try lifting inline functions one level up from render if possible. Alternatively use the callback wrapper for the anonymous function.

class App extends React.Component {
nameHandler = () => "foo"
render() {
<Incorrect name={() => "foo"} />
<Correct name={this.nameHandler} />
}
}

Same principles applies to using bind in render. Remember to always bind your handlers in the constructor since Function.prototype.bind will create a new function on every invocation.

class App extends React.Component {
constructor(props) {
super(props)
this.correctHandler = this.correctHandler.bind(this)
}
correctHandler() {
return "foo"
}
incorrectHandler() {
return "foo"
}
render() {
<Incorrect name={this.incorrectHandler.bind(this)} />
<Correct name={this.correctHandler} />
}
}
see example here

Context Provider

When a Context Provider re-renders, all of the child components in the tree are also being re-rendered. Even if a component is not consuming props from the context provider. Again, using the memo API can prevent the re-renders.

see example here

How Do I Even Track Rendering Of Components?

You can measure the rendering of a specific component simply by putting a console.log or console.count statement in the render method. If you have no clue where to start looking for potential unnecessary re-renders in your application then use the highlight updates feature in React DevTools. More on how to profile a React application can be found here and if you want to learn how to check the exact reason behind a certain re-render then it’s highlighted here.

I hope this article offered something whether you are a beginner or experienced React developer. I would be happy to answer questions or to discuss any React concepts or performance topics. Drop a comment below or find me on twitter.

--

--

Marcus Osterberg

Swedish. I like to code, learn new things and travel new places.