A problem we commonly face when using React is that of wasted renders. To conquer this problem, we need sophisticated tools that examine these problems to see why and how they occur – React Developer Tools provide just that.
In this shot, we will explore how we can leverage React Developer Tools to yet another good cause. But first, we have to know what a wasted render is.
A wasted render occurs when a component is re-rendered for no apparent reason.
All Components
in React have an internal state and properties called props that they maintain. Now, when either of these changes, common sense tells us that the Component
(s) should be re-rendered so the new states and props will reflect in the DOM.
If none of the state and props values have been changed, common sense also tells us that there is no need to re-render the component since neither the state nor the props values have changed.
Now, when a Component
is rendered when the state and the props have not changed, this is wasteful rendering. Our app might suffer from performance slowdowns.
This will be inconsequential when the Component
sub-tree is about five to ten components. However, when looking at the sub-tree on the scale of hundreds or thousands of components, the performance slowdown will be very apparent.
See this example:
class Count extends Component {
constructor() {
this.state = {
count: 0
}
}
render() {
return (
<div>
<div>Count: {this.state.count}</div>
<button onClick={() => this.setState({count: this.state.count + 1})}>Incr</button>
<button onClick={() => this.setState({count: this.state.count})}>No Incr</button>
</div>
)
}
}
We have a Component
that manages a local count
state. We have two buttons, Incr
and No Incr
, each of which has a click count
using the setState
method
Component rendering is mainly caused by the setState
method.
The Incr
button increases the count state by one and No Incr
sets the state to the current state value. However, either one would cause a re-rendering when clicked on in the Count
component. Incr
actually increases the count state, so the Component
should re-render to display the new count state.
No Incr
does not change the count state, and yet the Component
is re-rendered. On the initial rendering, the count state is zero when on No Incr
. If clicked, the state is set to itself, which is zero, and the component will re-render. Because the previous count state was zero, and the current count state is zero, so there should be no need for the component to re-render.
To verify this, let’s add a log message on the componentDidUpdate
and componentWillUpdate
lifecycle hook:
class Count extends Component {
constructor() {
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState){
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')
}
render() {
return (
<div>
<div>Count: {this.state.count}</div>
<button onClick={() => this.setState({count: this.state.count + 1})}>Incr</button>
<button onClick={() => this.setState({count: this.state.count})}>No Incr</button>
</div>
)
}
}
This will help us know when the component is updated.
Now open the Console on DevTools. Click on the No Incr
button twice. We will see two logs on our console:
componentWillUpdate
componentDidUpdate
That verifies that No Incr
triggers unnecessary re-renders, or wasted renders.
React Developer Tools is a DevTool extension that helps us debug, profile, and monitor our React app execution in our browser. It provides us with a highlighter that colors React component(s) boundaries whenever they are re-rendered.
We might not have the chance to add logs in componentDidUpdate
and componentWillUpdate
lifecycle methods of every component in our project to detect when an unnecessary render occurs.
React Developer Tools has a feature that can help us visualize components re-renders/updates.
Install the React Developer Tools extension
Now, whenever you load a React
app, a React
tab will appear on the DevTool:
Click on the React
tab. You will see a checkbox with the label “Highlight updates.” If you don’t see one, click on the settings icon, a modal will pop up, and there you will see a “Highlight updates” checkbox. If it is not checked, click on it to check.
Now, when a component updates, the boundaries of the component will be highlighted with a color.
There are different colors the React Dev Tool can show: blue, green, yellow, and red. They depend on the frequency of the components update. If a component is frequently updated, a red color highlight will be shown.
Let’s see a demo:
class Count extends Component {
render() {
return (
<div className="count">Count: {this.props.count}</div>
)
}
}
class Counter extends Component {
constructor() {
super()
this.state = {
count: 0
}
}
render() {
return (
<div className="counter">
<Count count={this.state.count} />
<button onClick={() => this.setState({count: this.state.count + 1})}>Incr</button>
<button onClick={() => this.setState({count: this.state.count})}>No Incr</button>
</div>
)
}
}
class App extends React.Component {
render() {
return (
<Counter />
)
}
}
export default App
This is still the same as our previous example, it’s just that we re-factored it. A Component
deals with displaying the count
state, except it all is still the same.
Now, run npm run
starts to serve the app. Then go to localhost:3000
to load the app in your browser.
Make sure the “Highlight Updates” box is ticked.
Click on the Incr
button, and we see a blue color appear around the Counter
and Count
components.
This shows that the Counter
and Count
components are updated.
Click on the No Incr
button; the blue color highlights the Counter
and Count
components.
These show that both Counter
and Count
are updating.
Now, let’s memoize our Counter
component to only update when the state and props have changed:
class Count extends React.PureComponent {
render() {
return (
<div className="count">Count: {this.props.count}</div>
)
}
}
class Counter extends React.PureComponent {
constructor() {
super()
this.state = {
count: 0
}
}
render() {
return (
<div className="counter">
<Count count={this.state.count} />
<button onClick={() => this.setState({count: this.state.count + 1})}>Incr</button>
<button onClick={() => this.setState({count: this.state.count})}>No Incr</button>
</div>
)
}
}
class App extends React.Component {
render() {
return (
<Counter />
)
}
}
export default App
We memoized Counter
and Count
by making them extend the React.PureComponent
. This feature makes the React Components
only re-render when the state and props value changes.
When we click on the Incr
button, it will display a blue highlight on the Counter
and Count
because the state value is changed every time it is clicked.
Now, click on the No Incr
button. There will be no color highlight appearing at all. This shows that no component was re-rendered/updated, which is good because there is no need for this, as no state or props were changed.
Regarding the color types, notice that the color highlights we saw above are all blue. This is because of how infrequently we press the buttons to re-render the components.
Now, click on the Incr
button rapidly and increase it gradually; you will see the color highlight change from blue to green to yellow and finally red.
This tool helps us easily identify in which part of our app re-rendering is happening.
This is another tool for your belt.
If you have any questions regarding this or anything I should add, correct or remove, feel free to comment, email, or DM me.
Free Resources