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!
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
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:
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
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
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
useMemo. Let’s look at some example code:
We can fix the app above can by changing just one line of code!
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.
React is a state management library. In most of the applications, you don’t need to use
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.
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.
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.
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.