Photo by Andy Hermawan on Unsplash
Make a lightning-fast React app⚡
Everyone loves a fast and smooth application. Let's see how you can get the best performance from your app without any external library.
Table of contents
- 3x jump in the performance 🚀
- Why re-calculate when you already know the answer?! 🤷🏻♂️
- The two hooks that will speed up your app 🏎️
- useMemo Hook — return the memoized value
- The flaw in the parent component 🧐
- useCallback Hook — return the memoized function
- Difference between useCallback & useMemo
- Everything comes at a price 💰
- Conclusion
The speed of your React app in the development and production environment is a night and day difference. Things look pretty impressive when working in a development environment, however, they can be far away from reality.
Creating an app is one thing but if it is not optimized you will lose your user's interest and the time and efforts you have given to develop it will be wasted.
This article will help you solve these problems and make your application work smooth in the real world. You will learn the correct ways to implement optimization to significantly increase performance.
3x jump in the performance 🚀
Let me show you a simple application before and after the optimization.
The Child component in this app is created in such a way that it should return a result after a 500 million loop cycle.
//loop inside the child component
let childCount = 0;
for (let i = 0; i < 500_000_000; i++) {
childCount++;
}
Check the render time of the child component for each render. It’s almost the same as the initial render.
Now, let me show you what happens after you add just one optimization method.
After adding just one optimization method you can see a significant difference in render time.
If you compare the average render time before the optimization is 1660ms and the average render time after optimization is 426ms which is approximately a 3x jump in performance.
Honestly, I didn’t expect this either. Even, I had to do this multiple times just to be sure it is because of the optimization. This is a crazy leap in performance 📈
Note: You may not get a 3x jump every time since it depends on the operations the app is performing. However, you will clearly see a significant difference after the optimizations.
Why re-calculate when you already know the answer?! 🤷🏻♂️
Before jumping on the actual code for optimization, let me show you the underlying principle of the optimizations, which will give you an idea of what’s coming later in this article.
Let’s see an example:
Suppose you are asked, what is the factorial of 5? And, if you are like me chances are you won’t remember the answer, so you calculate it which is totally fine. (Trust me, it’s fine!)
Factorial of 5 is 5 x 4 x 3 x 2 x 1 which is equal to 120
Now, let's say again you are asked the same question. Would you re-calculate it? No, right!
You had just calculated the factorial, it’s in your recent memory, you will say the answer right away which is 120.
That is what you want your app to do. Instead of doing heavy calculations every time, if your app can remember the previous result and can return the result directly instead of doing the calculation again, it can speed up the process by many folds.
That is what you will learn in this article, how to make your app remember the result and use its memory to save time and speed up the process. This is called Memoization.
The two hooks that will speed up your app 🏎️
Now the critical question is, how can you achieve this crazy speed? 🤔
Maybe you have to write some fancy code to get this optimization? or Maybe you can use a cool library to get it?
The answer is NO. You don’t need any of that. That is why I love React, it is very much focused on creating optimized applications.
React offers two hooks useMemo
and useCallback
which is solely for optimization purposes.
useMemo Hook — return the memoized value
The useMemo
hook in react is used to return a memoized or cached value to avoid unnecessary calculations.
This can improve the performance drastically. Let’s see how the above application used it to get such a performance boost.
You have already seen the loop inside the child component. Let me show you how you can use the useMemo
hook to optimize the loop.
//callback function
const memoizedCount = useMemo(() => {
let childCount = 0;
for (let i = 0; i < 500_000_000; i++) {
childCount++;
}
return childCount;
},[]);
//dependency array
The useMemo
hook cache the value when it runs for the first time. For the subsequent renders, it will return the cached value instead of running the loop, saving a lot of time. #missionaccompolished ✌️
The flaw in the parent component 🧐
Till now you have seen the code in the child component and how you can optimize it to get that mind-blowing speed. Now, its time to heat up the things 🔥
In the parent component, we have a button that on clicked increments the counter.
Looks pretty simple, right?! But the code behind it has a flaw, & it is such a simple thing that can be easily missed but can have a really big impact.
Note: The child component is wrapped inside the React memo HOC. React Memo is one of the most valuable tools when it comes to optimization. Check out the article by ordinarycoders to learn it in detail.
function App() {
const[count, setCount] = useState(0);
//function to handle the increment button click
const handleIncrement = () => {
setCount(prev => prev+1);
};
return (
<div className="App">
<h1>This is a test!</h1>
<h2>Counter : {count}</h2>
<Child increment={handleIncrement}/>
</div>
);
}
Did you find the flaw? No!
Okay, I will give you 30 seconds 🕣
You already know, that whenever there is a change in state, it triggers the re-rendering of the component, you will notice the handleIncrement function is defined inside the parent component.
When the parent component re-renders it will force the handleIncrement function to be re-defined.
But, what is the impact? 🤔
Even though the child component is wrapped inside the React Memo HOC, for the child component the handleIncrement function is a new prop every time the parent component re-renders which results in the unnecessary render of the child component.
useCallback Hook — return the memoized function
To resolve the above problem, you can use a React hook called useCallback
. It is similar to useMemo hook you have seen above. It takes 2 arguments, the first argument is the callback function and the second argument is the dependency array.
The useCallback
hook returns a memoized or cached version of the function instead of defining it for every render.
Let me show you the optimized code of the parent component 👇
function App() {
const[count, setCount] = useState(0);
const handleIncrement = () => {
setCount(prev => prev+1);
};
//callback function,dependency array
const handleIncrementOptimized = useCallback(() => handleIncrement(),[]);
return (
<div className="App">
<h1>This is a test!</h1>
<h2>Counter : {count}</h2>
<Child handleClick={handleIncrementOptimized} />
</div>
);
}
Instead of passing the handleIncrement function, you can pass the memoized function return by the useCallback
hook which will solve the unnecessary render problem.
You can see below, that the child component is only rendering for the first time.
The DOM operations are really expensive and if you can avoid such unnecessary operations, that will be remarkable. Your application is gonna fly ✈️
Difference between useCallback & useMemo
The structure of these two hooks are the same, both take two arguments, the callback function and the dependency array. The difference comes in the return value.
useMemo
hook returns the memoized “Value” whereas useCallback
returns the memoized “Function”
This is the simple difference between the two hooks and this difference decides the use case for both the hooks which you have seen with the example in this article.
Everything comes at a price 💰
You have seen the two hooks and how powerful tools they are when it comes to optimization. But this optimization does not come free.
To achieve this, React is trading the memory your application is using. How do you think it is doing the memoization?!
Along with adding these optimization techniques to your app, it is equally important to use them carefully. Otherwise, you will end up in a much worse condition.
Whenever, you are using any optimization technique always ask, “Whether it is required and how beneficial it is to the application performance?”
If you will be getting a significant bump in performance, do it. Otherwise, avoid.
Conclusion
I hope this article was helpful for you. Now it’s time to implement the optimization wisely and make a lighting-fast React app of your own.
Challenge: You have seen two hooks for the optimization in this article, comment down the other tools provided by React for optimization.
If you are interested in quick tips and bit-size content don’t forget to follow me on Twitter at anuragmathews08
Leave a 👍 if this article has provided some value to you.
That’s it for this article! Till the next time…. Happy Coding! ✌️