Performance Optimization with React Hooks and Memo
Improve application performance with functional components

Building a useful application is one thing, having the application load smoothly and quickly is something altogether else — and, arguably, of equal importance.
There are many way to go about optimizing an application in React to improve its performance.
Before we begin examining how to do this by building a simple app and implementing the memoization technique included in React Memo, let’s review the process of optimization.
Optimization is a process that’s most effective when measured against an initial model. If we are overly preemptive with optimization by implementing tools such as React Memo without having an initial measurement to compare to, we no longer provide ourselves the needed context to properly evaluate how, when, and where we’re making our improvements — thus failing to deliver proper optimization.
Patience and letting the process flow is key to successful optimizations and smooth running applications, young Padawan.
Therefore, it’s important for us to compare the differences of performance measurements.
In the following examples, we’ll look at a simple application leveraging React Hooks and measure the difference of performance with and without React Memo.
Feel free to code along and even follow the video demonstration at the bottom or to simply observe the differences in the documentation below. But first, let’s further define React Memo.
React Memo vs. PureComponent
React Memo is a higher-order component that wraps around functional components and improves their performance by memoizing them.
In this sense, it’s the solution for functional components that React.PureComponent
provides for class-based components.
Comparatively, each feature would be superficially introduced to their components, as seen below:
// PureComponent Class Based:
class Count extends React.PureComponent { }
Versus:
// React.Memo Functional Component:
const App = ({}) => {}export default React.memo(App)
How React Memo Works
React Memo improves performance by only rendering its wrapped component if the props have changed. However, it’s important to note that by default, React Memo will only shallowly compare complex objects in the props object.
We can further compare how this works by looking at an example use of the life-cycle method shouldComponentUpdate(nextProps, nextState)
.
We can utilize shouldComponentUpdate
to condition whether or not a component should update on the render based on checking if the nextProps
being updated are equal to the current props.
Although this implementation in effect works similarly to React Memo, the official React docs suggest not to use it to prevent rerendering — as it may lead to bugs. Instead, they suggest using its features designed to be more comprehensive, ensuring there will be less potentially necessary steps skipped.
React Application Example
Let’s now examine a basic application and measure its performance pre- and postmemoization with React.Memo
using the React Dev Tools.
Say we have an application with two basic components: a button that increments consecutively on each click by one and a weather component that displays a city and the weather in that city.
First, examine a JavaScript file containing our Weather
child component with the following code:
Our simple functional component takes the destructured weather
property as its props and returns two p
tags, displaying further dot notation accessing city
and temperature
.
We include a console.log(‘Render’)
to demonstrate in our upcoming test how many times our application is rendering our weather application.
Simple enough. All right, now observe another JavaScript file that contains our button application and holds our parent state, which passes props into our child Weather
component.We will implement React Hooks to store our counter and set the increment.
Now when we load our development server and compile our application, we display a button and a 0
— along with the city of Miami
and its temperature at 80F
.
We also note in the Chrome DevTools Console that we receive the initial console.log
of the render from our Weather
component.

The problem here becomes evident whenever we click on the Increment button.
Clicking on the Increment button seven times returns the following results:


Implementing React.memo
Although our button is working and our state is being updated and displayed accordingly, our console is now showing that our Weather
component has been rendered seven times.
These are useless renders happening every time we click on the button because the properties of our Weather
component doesn’t need to change every time we change the state of the button, and this is costing us extra unnecessary computation.
So how can we solve this problem? Well you guessed it … React.memo
to the rescue!
Back in our weather application, we can wrap React.memo
around our export of Weather
, like such:
export default React.memo(Weather)
And it’s as simple as that. Now when we refresh our application and click on the Increment button seven times again. we’ll notice the following important change.


Our Weather
component is only rendered once although our button has been rendered seven times. We have effectively enhanced the performance of our application by successfully implementing memoization.
Let’s further demonstrate the measured differences of our optimization with React Developer Tools.
React Developer Tools Profiler
If you don’t already have React Developer Tools installed, you can do so by going to the link provided here.
Click on the blue button on the top-right corner to add the extension to Chrome.

Once the extension is added, you’ll now have added React components, including Profiler, to your console-developer toolbelt.

The Components option will open up a tab where we can examine the individual components in our React Application being rendered on the browser, much like the Elements tab examines the elements.

Our Weather
component now displays to us the props of weather in our application. That’s great. However, for the purposes of this demonstration, let’s move onto the Profiler to measure the performance of our render times.
Let’s refresh the application in the browser. Then, in our Profiler tab, if we click on the record circle, we’re now recording the render times of our components. Let’s click on the increment button six times and then hit the record button again to record our measurements.

We now see our Weather
component, wrapped in (Memo)
, is displayed along with the status “Did not render during the profile session.”
Now, let’s repeat the same process again — only this time, we’ll remove the React.memo
higher order component from our child Weather
component.
We’ll now see six new renders of our Weather
component per each application render, averaging each at about one extra millisecond per render.

By measuring our render differences with the React Developer Tools GUI, we’re able to more deeply see the varying results. We withhold useless renders, leveraging React.memo
into our application.
Conclusion
By first building our application without preemptively applying optimizations and instead having an initial comparison value, we’re able to measure our performance with our own test implementations — as well as bring in helpful extensions such as the React Developer Tools.
With these results, we can then review the performance of our application and devise methods and features for enhancement and optimization. Measuring against previous results will lead us to dive deeper into our applications and find the best solutions we need for our optimization.
For additional resources, please check out the Performance Optimization section on React Dev 2020, which inspired this documentation I’ll link below.
For more information on memoization, you can check out a previous piece and example I wrote on reviewing memoization in Javascript below as well.
Finally, I’ll also link to a video tutorial as well as source code.
And that’s it. Thanks for checking this out, and I hope you found some of this helpful!