Yeah hooks are good, but have you tried faster React Components?

5 simple tips to improve the performance of a React application

Illustration by Omar Benseddik
  1. When does a render happen?
  2. What happens during a render?

About the render function

Which render function?

If you write your component using a class, then by render function, I am referring to the render method of the class:

class Foo extends React.Component { render() {
return <h1> Foo </h1>;
}

}
function Foo() {
return <h1> Foo </h1>;
}

When does render happen?

The render function of a component Foo is called in 2 cases:

What happens in the render function?

Two steps happen in order whenever the render function is called. It’s very important to understand both steps in order to know how to optimize a React application:

Tip #1: Avoid unnecessary render calls by carefully distributing the state

Let’s consider the following example, where App renders two components:

  • List , which receives a list of items.

Tip #2: Make fewer state updates

Since every state update leads to a new render call, having fewer state updates leads to fewer render calls 🤷‍♂.

// initial state
{ limit: 7, numbers: [0, 1, 2, 3, 4, 5, 6]
// change limit -> 4
render 1: { limit: 4, numbers: [0, 1, 2, 3, 4, 5, 6] } //
render 2: { limit: 4, numbers: [0, 2, 3]
  • We have inconsistent renders where the numbers don’t match the limit.

Tip #3: Avoid unnecessary render calls with PureComponent and React.memo

We saw in the previous example that in some cases, placing certain state values lower in the tree hierarchy helps avoid unnecessary render calls. Unfortunately, that is not always possible.

const Bar = React.memo(function Bar({name}) {
return <h1>{name}</h1>;
});
class Bar extends React.PureComponent {
render() {
return <h1>{name}</h1>;
}
}

Should every component be a PureComponent or memo?

If the previous tip avoids us unnecessary re-renders, why don’t we just PureComponent for every class component and React.memo for every functional one? Why do we even have React.Component if there is already a better version of it? Why isn’t every functional component memoized by default?

Problem with nested objects

What do PureComponent and React.memo components do under the hood?

// expected behavior with primitive values
shallowCompare({ name: 'bar'}, { name: 'bar'}); // output: true
shallowCompare({ name: 'bar'}, { name: 'bar1'}); // output: false
// unexpected behavior with primitive values
shallowCompare({ name: {first: 'John', last: 'Schilling'}, {first: 'John', last: 'Schilling'}); // output: false

Problem with function props

Props can also have functions. In JavaScript, functions are also stored as references and shallowly compared based on the values of these references.

Tip #4: Writing better props

One way we can solve the previous problem is by writing our props differently.

<Bar firstName="John" lastName="Schilling" />
class App extends React.Component{  constructor(props) {
this.doSomethingMethod = this.doSomethingMethod.bind(this);
}
doSomethingMethod () { // do something}

render() {
return <Bar onSomething={this.doSomethingMethod} />
}
}

Tip #5: Controlling the update

Tip #3 solves the unnecessary update problem. Unfortunately, we can’t always apply it.

const Bar = React.memo(
function Bar({ name: { first, last } }) {
console.log("update");
return (
<h1>
{first} {last}
</h1>
);
},
(prevProps, newProps) =>
prevProps.name.first === newProps.name.first &&
prevProps.name.last === newProps.name.last
);

Conclusion

The performance of React application is not limited to the use cases shown in this article. There are obviously other things to consider, such as the bundle size. However, keeping these tips in mind can make a huge difference in terms of performance.

Web Developer · #javascript #html5 #css3 · Writing about @react & @reasonml. https://t.co/TNMJNkLNgC · https://t.co/UYPVJ7MFY2