← Back to Chapters

React.memo()

? React.memo()

? Quick Overview

React.memo() is a higher-order component (HOC) used to optimize React functional components. It memoizes the rendered output and prevents unnecessary re-renders when the component's props have not changed, essentially acting as the functional equivalent of PureComponent in class-based React.

? Key Concepts

  • Memoization: Caches the result of a function render based on inputs (props).
  • Shallow Comparison: By default, it shallowly compares new props with old props.
  • Performance: Improves application speed by skipping rendering for sub-trees that haven't updated.
  • Usage: Wraps a functional component export.

? Syntax / Theory

? View Code Example
// Basic syntax wrapping a component
const MemoizedComponent = React.memo(MyComponent);

// Syntax with custom comparison function
const MemoizedComponent = React.memo(MyComponent, arePropsEqual);

? Code Examples

1. The Child Component (Memoized)

? View Code Example
// Child.js - This component only re-renders if 'name' changes
import React from "react";

const Child = ({ name }) => {
  console.log("Child Rendered");
  return <div>Hello, {name}!</div>;
};

// Export the component wrapped in React.memo
export default React.memo(Child);

2. The Parent Component

? View Code Example
// Parent.js - Manages state
import React, { useState } from "react";
import Child from "./Child";

const Parent = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("User");

  return (
    <div>
      <h1>Count: {count}</h1>
      
      // Clicking this updates Parent state but NOT Child props
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      
      <Child name={name} />
    </div>
  );
};

export default Parent;

⚙️ Custom Comparison Logic

Sometimes shallow comparison isn't enough (e.g., nested objects). You can pass a second argument to control exactly when to re-render.

? View Code Example
// Custom comparison function
function arePropsEqual(prevProps, nextProps) {
  // Return true if passing nextProps to render would return
  // the same result as passing prevProps to render,
  // otherwise return false
  return prevProps.userId === nextProps.userId;
}

export default React.memo(ProfilePage, arePropsEqual);

? Live Output / Explanation

Visualizing the Flow

Without Memo: Parent renders ➜ Count updates ➜ Parent Re-renders ➜ Child Re-renders (wasted).

With Memo: Parent renders ➜ Count updates ➜ Parent Re-renders ➜ React checks Child props ➜ Props are same? ➜ Skip Child Re-render.

? Interactive Simulation

Control the parent state and observe when the child component "flashes" (re-renders).

Renders: 0

Parent Component

State (Count): 0

Renders: 0

Child Component

Prop (Name): User

*A yellow flash indicates a re-render occurred.

? Use Cases

  • Heavy Rendering: Components that contain complex UI logic or large DOM trees.
  • Frequent Parent Updates: When a parent component updates often (e.g., on every keystroke) but the child only relies on static data.
  • Pure Functional Components: Components that render the same output given the same props.

? Tips & Best Practices

  • Don't Prematurely Optimize: Only use React.memo if you spot performance issues. Memoization has its own cost.
  • Callback Props: If passing functions as props, use useCallback in the parent, or React.memo will see a "new" function every time and re-render anyway.
  • Reference Types: Be careful with objects/arrays in props; they are new references on every render unless memoized.

? Try It Yourself

  1. Create a parent component with a timer that updates every second.
  2. Add a static child component that just displays a title.
  3. Add a console.log in the child.
  4. Wrap the child in React.memo and watch the console logs stop appearing every second.