Editor’s note: This post was updated on 21 November 2023 to incorporate information about the React functional component lifecycle and React stateless function components.
In this tutorial, we’ll learn how to memoize functional components in React using React.PureComponent
and the React.memo
API. We’ll cover some of the fundamentals of React components before we dive into an example.
You can keep up with the changes and suggestions for the React framework on the React RFCs repository.
Like most modern JavaScript frameworks, React is component-based. A component is usually defined as a function of its state and props.
React supports two types of components: class components and functional components. A functional component is a plain JavaScript function that returns JSX. A class component is a JavaScript class that extends React.Component
and returns JSX inside a render method.
The following code snippet shows a simple ReactHeader
component defined as both a class component and a functional component:
// CLASS COMPONENT class ReactHeader extends React.Component { render() { return ( <h1> React {this.props.version || 17} Documentation </h1> ) } } // FUNCTIONAL COMPONENT function ReactHeader(props) { return ( <h1> React {props.version || 17} Documentation </h1> ) }
Based on the concept of purity in functional programming paradigms, a function is said to be pure if it meets the following two conditions:
A React component is considered pure if it renders the same output for the same state and props. For this type of class component, React provides the PureComponent
base class. Class components that extend the React.PureComponent
class are treated as pure components.
Pure components have some performance improvements and render optimizations because React implements the shouldComponentUpdate()
method for them with a shallow comparison of props and state.
In practice, a React pure component looks like the following code:
import React from 'react'; class PercentageStat extends React.PureComponent { render() { const { label, score = 0, total = Math.max(1, score) } = this.props; return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } } export default PercentageStat;
Functional components are very useful in React, especially when you want to isolate state management from the component. That’s why they are often called stateless components.
However, functional components cannot leverage the performance improvements and render optimizations that come with React.PureComponent
because, by definition, they are not classes.
If you want React to treat a functional component as a pure component, you’ll have to convert the functional component to a class component that extends React.PureComponent
.
Check out the simple example below:
// FUNCTIONAL COMPONENT function PercentageStat({ label, score = 0, total = Math.max(1, score) }) { return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } // CONVERTED TO PURE COMPONENT class PercentageStat extends React.PureComponent { render() { const { label, score = 0, total = Math.max(1, score) } = this.props; return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } }
React stateless function components are functions that do not manage any state. They are a simple way to define components that don’t need to manage state or lifecycle methods.
In essence, stateless function components are JavaScript functions that return React items after receiving props as input. Stateless functional components are used when a component doesn’t need to maintain its own state or lifecycle methods.
Typically, these components have consistent output based on their inputs because they have no state or side effects.
If you give a stateless function component a set of props, it will always render the same JSX. A simple example is:
const Title = ({ title }) => { return <h1>{title}</h1>; };
While functional components don’t have direct lifecycle methods, they still go through the same three phases as class components:
useEffect(() => {}, [])
: This Hook is similar to componentDidMount
in class components. The function inside useEffect
runs after the component is first rendereduseEffect(() => {})
: If you omit the dependency array ([]
), useEffect
will run after every render (similar to componentDidUpdate
)useEffect(() => { return () => {} })
: The function returned inside useEffect
(the cleanup function) is equivalent to componentWillUnmount
in class components and is used to clean up resources when the component unmounts or before it re-renders{ pure }
HOC from RecomposeOptimizing a functional component so that React can treat it as a pure component shouldn’t necessarily require that you convert the component to a class component.
The Recompose package provides a broad collection of higher-order components (HOCs) that are very useful for dealing with functional components. The Recompose package exports a [[{ pure }]]
HOC that tries to optimize a React component by preventing updates on the component unless a prop has changed, using shallowEqual()
to test for changes.
Using the pure HOC, our functional component can be wrapped as follows:
import React from 'react'; import { pure } from 'recompose'; function PercentageStat({ label, score = 0, total = Math.max(1, score) }) { return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } // Wrap component using the `pure` HOC from recompose export default pure(PercentageStat);
React.memo
With React.memo
, you can create memoized functional components that prevent unnecessary updates. This functionality is particularly useful when dealing with components that receive the same set of props. React.memo
does this by comparing the new and previous props using a shallow comparison.
Using the React.memo
API, the previous functional component can be wrapped as follows:
import React, { memo } from 'react'; function PercentageStat({ label, score = 0, total = Math.max(1, score) }) { return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } // Wrap component using `React.memo()` export default memo(PercentageStat);
React.memo
API implementation detailsThere are a few things worth considering about the implementation of the React.memo
API.
For one, React.memo
is a higher-order component. It takes a React component as its first argument and returns a special type of React component that allows the renderer to render the component while memoizing the output. Therefore, if the component’s props are shallowly equal, the React.memo
component will bail out the updates.
React.memo
works with all React components. The first argument passed to React.memo
can be any type of React component. However, for class components, you should use React.PureComponent
instead of React.memo
. React.memo
also works with components rendered from the server using ReactDOMServer
.
The React.memo
API can take a second argument, the arePropsEqual()
function. The default behavior of React.memo
is to shallowly compare the component props. However, with the arePropsEqual()
function, you can customize the bailout condition for component updates. The arePropsEqual()
function is defined with two parameters: prevProps
and nextProps
.
The arePropsEqual()
function returns true
when the props are compared to be equal, thereby preventing the component from re-rendering, and it returns false
when the props are not equal.
The arePropsEqual()
function acts very similar to the shouldComponentUpdate()
lifecycle method in class components but in the reverse manner. The following code snippet uses a custom bailout condition:
import React, { memo } from 'react'; function PercentageStat({ label, score = 0, total = Math.max(1, score) }) { return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } function arePropsEqual(prevProps, nextProps) { return prevProps.label === nextProps.label; } // Wrap component using `React.memo()` and pass `arePropsEqual` export default memo(PercentageStat, arePropsEqual);
We use the strict equal operator ===
because we want to check the equality between the values and their types without conversion. For example, "1"
and 1
are not the same. Loose equality between them will return true, "1" == 1 // true
. But, strict equality will be false, "1"=== 1 // false
. So, we want to perform strict comparison.
With the React.memo
API, you can enjoy the performance benefits that come from using functional components together with optimizations that come with memoizing the components.
In this article, we explored the React.memo
API in detail. First, we covered the differences between functional and class components in React, and then we reviewed pure components, learning how to convert a functional component to a class component.
I hope you enjoyed this article. Be sure to leave a comment if you have any questions. Happy coding!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
7 Replies to "What are React pure functional components?"
“Speaking about JavaScript frameworks at such a time as this can never be complete if nothing is said about the React framework created and maintained by the team at Facebook.”
React is not a framework, it’s a UI-library for creating re-usable components.
You’re technically right, but it’s a meaningless distinction IMO. If you’d like to write a post for the blog explaining why it’s not a meaningless distinction, I’d be happy to publish it.
Good article, thanks.
Well explained details in the article, I managed to solve a performance issue based on this post!
Why we call react a framework ?
Is it because it became so popular, that it replaced angular in many real world projects…
angular is framework, so we call react also a framework
React is a library not a framework
Appreciate the way this article explains. I have been searching for “how to write pure components wo using class”. hardly any articles available.. This is very well articulated.
Thanks.