How to Use React.memo for Performance Optimization
Use
React.memo to wrap a functional component so React skips re-rendering it when its props have not changed. This improves performance by avoiding unnecessary updates for components with stable props.Syntax
React.memo is a higher-order component that takes a component and returns a memoized version of it. It only re-renders the component if its props change.
Basic syntax:
React.memo(Component): Wraps the component.Component: Your functional component.- Optional second argument: a function to customize prop comparison.
javascript
const MemoizedComponent = React.memo(Component); // With custom comparison const MemoizedComponent = React.memo(Component, (prevProps, nextProps) => { // return true if props are equal (skip render) // return false if props changed (re-render) });
Example
This example shows a parent component rendering a child wrapped with React.memo. The child only re-renders when its count prop changes, even if the parent re-renders for other reasons.
javascript
import React, { useState } from 'react'; const Child = React.memo(({ count }) => { console.log('Child rendered'); return <div>Count: {count}</div>; }); export default function App() { const [count, setCount] = useState(0); const [text, setText] = useState(''); return ( <div> <Child count={count} /> <button onClick={() => setCount(count + 1)}>Increment Count</button> <input value={text} onChange={e => setText(e.target.value)} placeholder="Type here" /> </div> ); }
Output
When you type in the input, 'Child rendered' does NOT log because Child does not re-render.
When you click 'Increment Count', 'Child rendered' logs because count changed.
Common Pitfalls
Common mistakes when using React.memo include:
- Wrapping components that always receive new props (like new objects or functions) causing memo to fail.
- Not using a custom comparison function when props are complex objects.
- Using
React.memoon components that are cheap to render, which adds unnecessary overhead.
Always ensure props are stable or use useCallback and useMemo to keep props referentially equal.
javascript
import React, { useState, useCallback } from 'react'; const Child = React.memo(({ onClick }) => { console.log('Child rendered'); return <button onClick={onClick}>Click me</button>; }); export default function App() { const [count, setCount] = useState(0); // Wrong: new function created every render, memo fails // const handleClick = () => setCount(c => c + 1); // Right: useCallback keeps function stable const handleClick = useCallback(() => setCount(c => c + 1), []); return <Child onClick={handleClick} />; }
Output
Without useCallback, 'Child rendered' logs every render.
With useCallback, 'Child rendered' logs only once unless dependencies change.
Quick Reference
- Use React.memo to wrap functional components to skip re-renders when props are unchanged.
- Use useCallback and useMemo to keep props stable and help memo work effectively.
- React.memo only shallowly compares props, so use a custom comparison function for deep checks.
- Don't overuse React.memo on simple or fast-rendering components.
Key Takeaways
Wrap functional components with React.memo to prevent unnecessary re-renders when props don't change.
React.memo does a shallow prop comparison; use a custom comparator for complex props.
Keep props stable using useCallback and useMemo to maximize React.memo benefits.
Avoid using React.memo on components that render quickly or rarely re-render.
React.memo improves performance by reducing rendering work but adds slight overhead.