React is performant! But sometimes it’s not

Suspense and code-splitting

Are re-renders that bad?

Memoize all the things!

State management

We know the basics now

I’ve been using React for quite some time now, doing projects small as landing pages for startups and massive as e-commerce with millions of users. In this post, I would like to share with you some of my thoughts on React performance. I hope you’ll like it!

React is performant! But sometimes it’s not

JavaScript libraries have their pitfalls. Authors always try, to limit those, but often it is the user’s fault to fall into those traps. It is no different with React. After years of using it, solving lots of bugs and dealing with demanding clients, I can confidently say that frequently your app is slow because of you! Let’s dig into some React performance-focused features!

Suspense and code-splitting

In many apps, you will find some components that seem heavy. Consider some charts, graphs or visualizations. Our users don’t have to wait for those to load on the registration page! It often happens in vast, real-world applications, that all the components load on each page. React apps are Single Page Applications, routing is framework based. If there are many large and heavy components, the whole application seems laggy.

This is when code-splitting comes handy. It relays on the principle that less code to load makes the app faster. In React, we can combine lazy and Suspense to load components as lazy modules.

First, we have to export the component as default from the module. Secondly, we use lazy to load the component. Suspense is used to fallback into the loading component. Here’s how to do it:

And here’s the usage:

Are re-renders that bad?

The shortest answer: No.
But they can be.
Document Object Model is slow. If component re-render causes DOM to update each time, it is quite bad. Consider the following code:

Of course, I should have wrapped setTimeout in useEffect, but this is only an example of an expensive operation.

Each re-render here causes expensive operation in the Spinner component. That’s bad.

Let us fix it with a simple trick!

That’s better! Only a single expensive operation!

Remember to use Chrome’s Dev Tools and React Dev Tools to find what parts of your app cause slow re-renders and fix them.

Always consider better architecture before flooding your code with React.memos.

color-orb
color-orb

Memoize all the things!

Sometimes components need to do some expensive calculations. React gives us the ability to memoize or remember/cache expensive calculation output. This feature is called useMemoLet’s look at some example code:

We can fix the app above can by changing just one line of code!

code before
Replace calculateSum(x, y)
code after
with useMemo!

This one is a game-changer!

As far as useMemo goes, it is still restrained by the React hooks rules, so it can only be called from React functional component or React custom hook. If we want to memoize the whole component, we can use other React feature – React.memo. People can make the slip of enclosing everything in React.memo which can actually make your app slower! Please, always use it on purpose.

State management

React is a state management library. In most of the applications, you don’t need to use Redux, MobX, Rematch, Recoil etc. Believe me, React is enough. In real-world apps, we can fall into a situation when so many components are updated when the state changes that it becomes a performance bottleneck. There are some great ways to fix that problem.

Shared state

First of all, if the state is shared between sibling components or a parent and a child component, we can lift the state to the parent component.

Secondly, if the state is used only by a single child component, we can colocate it. It means to move the state directly to that specific child component.

Context

The third option is to move the state into React context. Keep in mind that all Context Consumers get re-rendered on each context value change. I suggest putting the Context Provider close to where it’s relevant as possible. Of course, there are some Providers that you want to put on top of your application, it doesn’t mean that you should put all providers there.

The key to state management in React is not complicated: keep it where it’s necessary.

We know the basics now

Those four problems that I covered above are all solved by simple React tricks. There are also performance issues that we can tackle by using some great libraries. This will be the topic of my next post.

I hope that using React features correctly will make your applications more performant.

color-orb
color-orb

Other worthy reads