- React Tutorial
- React Home
- React Setup
- React Introduction
- React ES6
- React Render HTML
- React JSX
- React Components
- React Class
- React Props
- React Events
- React Conditional
- React Lists
- React Forms
- React Router
- React Memo
- React CSS Styling
- React Hooks
- What is a Hook?
- React useState
- React useEffect
- React useContext
- React useRef
- React useReducer
- React useCallback
- React useMemo
- React Custom Hooks
React Memo
- React.memo is a higher-order component (HOC) designed to optimize performance by memoizing the output of functional components.
- It tells React to skip re-rendering a component if its props haven't changed, saving precious CPU cycles on complex UI updates.
In a standard React application, when a parent component re-renders, all of its children re-render by default—even if those children didn't receive any new data. While React is very fast at updating the virtual DOM, these "unnecessary" re-renders can accumulate and cause lag in large applications. React.memo acts as a guard, ensuring a component only updates when it absolutely needs to.
React.memo. Use it strategically for components that render often with the same props or components that are computationally "expensive" to render.
Basic Usage
To use React.memo, you simply wrap your functional component definition with it. This creates a "memoized" version of that component.
import React from 'react';
const UserProfile = React.memo(({ name, bio }) => {
console.log("Rendering UserProfile...");
return (
<div>
<h2>{name}</h2>
<p>{bio}</p>
</div>
);
});
export default UserProfile;
React.memo for "Pure" components—those that always render the same output given the same props and don't rely on frequently changing global state or side effects.
Default Behavior
By default, React.memo performs a shallow comparison of the props object. It looks at every prop and checks if the new value is strictly equal (===) to the old value.
import React, { useState } from 'react';
import UserProfile from './UserProfile';
const Dashboard = () => {
const [count, setCount] = useState(0);
const [user] = useState({ name: 'Alex', bio: 'Software Engineer' });
return (
<div>
<h1>Dashboard</h1>
<button onClick={() => setCount(count + 1)}>Clicked {count} times</button>
{/* Even if Dashboard re-renders due to 'count', UserProfile won't re-render
because 'user' props remain the same. */}
<UserProfile name={user.name} bio={user.bio} />
</div>
);
};
<Component onClick={() => doSomething()} />. This breaks memoization because the function is technically "new" every time the parent renders. Use useCallback to fix this.
Custom Comparison Function
Sometimes a shallow comparison isn't enough. You might want to ignore certain prop changes or perform a deep comparison on specific objects. React.memo accepts a second argument: a comparison function.
import React from 'react';
const ProjectDetails = ({ project }) => {
return (
<div>
<h3>{project.title}</h3>
<p>Last updated: {project.lastModified}</p>
</div>
);
};
const areEqual = (prevProps, nextProps) => {
// Only re-render if the project ID or the lastModified timestamp changes
return (
prevProps.project.id === nextProps.project.id &&
prevProps.project.lastModified === nextProps.project.lastModified
);
};
export default React.memo(ProjectDetails, areEqual);
shouldComponentUpdate in class components. Return true if the props are equal (don't render) and false if they are different (do render).
Use Cases for Memoization
Memoization is most beneficial in scenarios where UI elements are repetitive or computationally heavy. Common real-world examples include:
- Large Lists: Individual list items in a long scrollable list.
- Data Visualizations: Components rendering complex SVG charts or Canvas elements based on specific data.
- Static UI Sections: Headers, footers, or sidebars that stay the same while the main content area changes rapidly.
import React from 'react';
// An item in a list of 1,000 items
const ListItem = React.memo(({ item, onSelect }) => {
return <li onClick={() => onSelect(item.id)}>{item.label}</li>;
});
const InventoryList = ({ items, handleSelect }) => {
return (
<ul>
{items.map(item => (
<ListItem key={item.id} item={item} onSelect={handleSelect} />
))}
</ul>
);
};
Avoiding Unnecessary Re-renders
The primary goal of React.memo is to stop the "render ripple effect." When a top-level state changes (like a timer or a search input), it can trigger hundreds of child re-renders. Memoization stops the ripple at the components that don't need to change.
React.memo actually makes your app slightly slower.
Considerations
- Prop Complexity: Memoization works best when props are simple strings, numbers, or booleans. If props are complex objects, ensure you are maintaining referential identity (using
useMemoin the parent). - Component Logic: If a component has internal state (
useState) or subscribes to a context (useContext), it will still re-render when that state or context changes, regardless ofReact.memo.
Summary
Using React.memo is a powerful way to optimize React applications by selectively preventing re-renders of components. It is particularly useful for pure functional components that receive stable props. By understanding the difference between shallow and deep comparisons, and knowing when to apply this HOC, you can significantly improve the "feel" and responsiveness of your web applications.
React.memo.