If you’ve been developing websites over the past few years, you’ve surely heard of React, a Javascript library for developing complex, interactive UIs. Originally developed at Facebook and launched publicly in 2013, React had numerous advantages over existing Javascript libraries and frameworks including a component-driven architecture and a virtual DOM for increased performance.
Even though React made building performant web applications much easier, some interfaces still needed a bit of a performance boost. This is where React.memo()
comes in.
In this article, we’ll take a look at what React.memo()
is and how to best use it to make your React frontend more performant.
Some important React concepts
Before we dive into React.memo()
specifically, it’s important to understand how React renders interfaces. There are two important concepts that affect your React UIs.
React components
Interfaces in React are made up of components that contain all the display properties and logic for a particular element. Passing data between these components is done by way of properties, or props. When a component is rendered, it can be provided with props, which are essentially parameters containing values or functions. These props can be accessed within the component and used to customize its behavior or display specific data. Passing different props to a component will cause it to render differently or even conditionally render depending on how the props are passed and what data exists in the state of the application.
Making sure these render updates stay performant is the responsibility of another important piece of React: the virtual DOM.
Virtual DOM
The Virtual DOM in React is a concept that helps keep applications performant by minimizing unnecessary updates to the actual browser DOM. It works by creating a representation of the DOM called the Virtual DOM, which mirrors the actual DOM structure. When changes are made to the application's state or props, React compares the new Virtual DOM with the existing one, identifies the differences, and calculates the most efficient way to update the actual DOM. This reconciliation process significantly reduces the number of direct manipulations to the DOM, resulting in faster and more efficient rendering of components, which improves the overall performance of a React application.
When these two concepts aren’t enough
Both the component architecture of React and the virtual DOM come together to make it easy to create performant web frontends. However, there are some cases where even deciding whether to re-render a component is computationally expensive and slows down the performance of your application. Ideally, in these scenarios, you could know ahead of time that the component didn’t need to re-render and you could skip this computation entirely to make your application more performant as a result. That’s where React.memo()
comes in.
What is React memo?
React.memo()
is a piece of the React codebase that allows React to skip re-rendering of components when the props are unchanged. A standard React component will re-render every time its parent component re-renders. With React.memo
, you can create what’s known as a “memoized component”, which won’t re-render as long as the props passed to that component are unchanged.
Especially for components that are computationally expensive to render, not re-rendering them unnecessarily can be a huge performance boost to your application.
How does React memo work?
Memo, in this case, is short for memoization, which is a concept in the broader field of computer science. Memoization is the process of storing the result of expensive function calls or computations and re-using the stored results instead of recomputing the results each time the computation is needed, as long as the inputs are the same.
This concept translates to React quite nicely. Since the inputs to a React component are props, a memoized component can confidently return a previously-saved render state as long as the props that are passed into the given component are the same as when that render state was generated and saved.
One thing that’s important to note is that, while simply comparing the props passed to a component seems simple when you think of props that are a string or an integer, props can be more complex data types such as arrays and objects as well. When comparing props, React.memo()
performs a shallow comparison. A shallow comparison means that it checks for equality at the top level of the props object, comparing the values directly. It does not perform a deep comparison of nested objects or arrays within the props.
With that in mind, let’s take a look at a couple real-world examples where React.memo()
could be helpful.
Real-world impact
To understand how React.memo()
might be helpful, let’s consider a <List>
component with nested <ListItem>
components. If you expect this list to potentially contain a large number of items, you could run into a situation where the List component becomes less performant because of all the re-renders of the contained ListItem components. Imagine a ListItem component looked something like the following:
This is a standard React component that accepts props for the title and the description. Especially if we think this component might be used inside a very large list, we want to make sure that it doesn’t re-render when it doesn’t need to - that is, specifically when the title and description have not changed.
Refactoring this component to use React.memo()
and ensure that it doesn’t re-render when none of the props have changed would look something like this:
Especially as the number of elements in your application grows, introducing React.memo()
for complex components can help keep your application performant.
Limitations and drawbacks
As useful as it is, React.memo()
shouldn’t be used on every component and, in some cases, can even harm an application’s performance.
If you’re either not sure of the performance benefits or the benefits are so insignificant that they’re not quantifiable, you shouldn’t use React.memo()
. This is to avoid adding complexity to your codebase in exchange for no tangible performance benefit.
The second important piece to consider when deciding whether React.memo()
is right for a particular component relates to the fact that memo performs a shallow comparison. If you have complex props being passed to a particular component, you could run into a case where the shallow comparison decides the props haven’t changed when in fact they have. This would mean that React.memo()
would return the memoized component instead of re-rendering, even though a new render is actually required in this ace. This can be a non-obvious problem and is something to avoid if at all possible.
Airplane as a solution for building performant React UIs
Whether you use React.memo()
for your components or not, if you’re looking for a library of pre-built components to help you build interfaces for your admin panels, internal tools and workflows, consider Airplane.
Airplane now has Views, which let you snap together Airplane’s React components or bring your own to create powerful interfaces to help you and your teammates get more done, faster. Check out the documentation for the full component library including tables, charts, icons, navigation, and more.
Airplane also provides templates with ready-made solutions that take just seconds to duplicate, such as the admin panel template.
If you're interested in trying out Airplane, you can sign up for a free account to get started. If you have any questions, feel free to reach out to us at anytime at [email protected]!