In React, unnecessary re-renders can occur when the parent component re-renders, even if the child component's props haven't changed. This can lead to performance issues, especially in complex applications. One way to prevent this is by using React.memo(), which helps memoize a component. This means React will only re-render the component if its props have changed.
In this example, let’s assume we can't move the count state to a separate component because it's needed in the parent App component. However, we can still optimize the List component by using React.memo() so it only re-renders when the people prop changes.
Before Using React.memo()
Without optimization, every time the count state changes in the parent App component, the App re-renders. This also causes the List component to re-render, even though the people prop passed to List hasn't changed. This is inefficient.
App.jsx (Before Using React.memo()):
import { useState } from 'react';
import { data } from '../../../../data';
import List from './List';
const App = () => {
const [people, setPeople] = useState(data);
const [count, setCount] = useState(0);
return (
<section>
<button
className='btn'
onClick={() => setCount(count + 1)}
style={{ marginBottom: '1rem' }}
>
count {count}
</button>
<List people={people} />
</section>
);
};
export default App;
-
Problem:
Every time the
countstate changes, theAppcomponent re-renders. This also causes theListcomponent to re-render, even though thepeopleprop hasn't changed.
Visual Example:
Before: List re-renders unnecessarily when count changes.

After Using React.memo()
To optimize this, we can wrap the List component with React.memo(). This will ensure that List only re-renders when its people prop changes, not when the count state changes.
List.jsx (After Using React.memo()):
import { memo } from 'react';
import Person from './Person';
const List = ({ people }) => {
return (
<div>
{people.map((person) => {
return <Person key={person.id} {...person} />;
})}
</div>
);
};
// Memoize the List component
export default memo(List);
-
How it works:
-
React.memo()compares thepeopleprop of theListcomponent. Ifpeoplehasn’t changed, React skips re-renderingList. -
Listwill only re-render when thepeopleprop changes, even if the parentAppcomponent re-renders due to thecountstate change.
-
Visual Example:
After: List re-renders only when the people prop changes, not when count changes.

Performance Improvement
By using React.memo(), we prevent unnecessary re-renders of the List component when the count state in the parent App component changes. This leads to a more efficient rendering process, especially in applications with large datasets or complex UIs.
Summary
-
React.memo()is a higher-order component that helps prevent unnecessary re-renders by memoizing the component. - In this example, we wrapped the
Listcomponent withReact.memo()so it only re-renders when thepeopleprop changes, not when the parentAppcomponent's state changes. - This optimization is useful for improving performance, particularly when the parent component frequently re-renders but the child component's props remain unchanged.
Top comments (1)
MIND GRENADE!!! 💣
Imagine we need to add a
removePersonmethod to remove a person from a list. So, let’s start with the basic setup inApp.jsx:App.jsx
In this code, we’re removing a person by filtering the
peoplearray, and passing theremovePersonfunction down to theListcomponent.List.jsx (Memoized Component)
We use
memohere to memoize theListcomponent, so it only re-renders if thepeopleorremovePersonprops change.Person.jsx (Displaying Each Person)
What’s the Problem?
Now, everything works fine when we remove a person—
Listre-renders because thepeoplearray changes. But what happens when we click the count button? 🤔The Unexpected Re-render!
When we click on the count button, the
removePersonfunction is re-created on each render. Because the function reference changes, it’s considered a new value by React. So, even though thepeoplearray hasn’t changed, theremovePersonfunction prop is treated as "changed," causing theListcomponent to re-render unnecessarily.The Memoization Breakdown
In the
Listcomponent, we usedmemo, which only prevents re-renders if the props change. However, the function passed as a prop (removePerson) is created from scratch every time theAppcomponent re-renders (because of thesetCountstate change). This means that React sees theremovePersonfunction as "changed" every time theAppre-renders.Here’s what happens:
Listshould not re-render if only thecountchanges and thepeoplearray stays the same.Listdoes re-render because theremovePersonfunction is recreated every time theAppcomponent re-renders.DevTools Insight
We can see this in the React DevTools Profiler. Even though the
peoplearray hasn’t changed, we can clearly see that theremovePersonfunction is treated as a prop change, triggering a re-render of theListcomponent.Here’s the breakdown:
removePersonfunction is created from scratch on every render, and React treats it as a new prop.Listto re-render, even though thepeopleprop hasn’t changed.Why Is This Happening?
memois working fine for checking props, but it doesn’t handle functions that are recreated on each render.The Solution:
useCallbackNext, we’ll introduce the
useCallbackhook, which will help us preserve the function reference across renders, preventing unnecessary re-renders in this scenario.With
useCallback, we can ensure thatremovePersononly gets recreated when the dependencies (likesetPeople) change, not every time the component re-renders.Stay tuned for the fix! 🔧
TL;DR:
useCallbackwill help us preserve the function reference and avoid unnecessary re-renders when only other state (likecount) changes.