React.memo, useMemo, useCallback — Step-by-Step

🧠 Why Use These?

React re-renders components whenever state or props change. But sometimes:

  • You don’t want a child to re-render if props didn’t change.
  • You want to avoid recalculating expensive functions.

That’s where these tools come in.

✅ 1. React.memo – Memoize Components

📌 What it does:

Wrap a component to prevent it from re-rendering unless props actually change.

🧾 Example:

import React from "react";

const Child = React.memo(({ name }) => {
  console.log("👶 Child rendered");
  return <p>Child Name: {name}</p>;
});

export default Child;

Use in Parent:

import React, { useState } from "react";
import Child from "./Child";

function Parent() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increase Count</button>
      <Child name="Alice" />
    </>
  );
}

export default Parent;

🧠 Output:

  • Even if count changes, Child won’t re-render unless name prop changes.

✅ 2. useMemo – Memoize Expensive Values

📌 What it does:

Only re-computes a value when dependencies change.

🧾 Example:

import React, { useState, useMemo } from "react";

function ExpensiveCounter() {
  const [count, setCount] = useState(0);
  const [dark, setDark] = useState(false);

  const slowFunction = (num) => {
    console.log("⚙️ Slow calculation...");
    for (let i = 0; i < 1000000000; i++) {} // fake delay
    return num * 2;
  };

  const doubleCount = useMemo(() => slowFunction(count), [count]);

  const themeStyles = {
    backgroundColor: dark ? "black" : "white",
    color: dark ? "white" : "black",
    padding: "20px",
    marginTop: "10px"
  };

  return (
    <>
      <button onClick={() => setCount((c) => c + 1)}>➕ Increment</button>
      <button onClick={() => setDark((d) => !d)}>🌓 Toggle Theme</button>
      <div style={themeStyles}>
        <h2>Double: {doubleCount}</h2>
      </div>
    </>
  );
}

export default ExpensiveCounter;

🧠 Without useMemo:

Toggling theme will re-run slowFunction unnecessarily.
With useMemo, it only runs when count changes.

✅ 3. useCallback – Memoize Functions

📌 What it does:

Returns the same function instance unless dependencies change.

🧾 Example:

import React, { useState, useCallback } from "react";
import List from "./List";

function App() {
  const [number, setNumber] = useState(1);
  const [dark, setDark] = useState(false);

  const getItems = useCallback(() => {
    return [number, number + 1, number + 2];
  }, [number]);

  const theme = {
    backgroundColor: dark ? "#333" : "#eee",
    color: dark ? "#eee" : "#333",
    padding: "20px"
  };

  return (
    <div style={theme}>
      <h1>useCallback Example</h1>
      <button onClick={() => setNumber((n) => n + 1)}>➕</button>
      <button onClick={() => setDark((d) => !d)}>🌗</button>
      <List getItems={getItems} />
    </div>
  );
}

📂 List.js

import React, { useEffect, useState } from "react";

function List({ getItems }) {
  const [items, setItems] = useState([]);

  useEffect(() => {
    console.log("📦 getItems changed");
    setItems(getItems());
  }, [getItems]);

  return items.map((item) => <div key={item}>{item}</div>);
}

export default List;

Without useCallback, getItems() is recreated every render and triggers useEffect unnecessarily.

purpose, differences, and when to use each one

🧠 Summary Table

FeatureWhat it doesUsed forReturnsCommon Use Case
React.memoMemoizes a componentAvoids re-renderComponentPrevent child component re-render if props same
useMemoMemoizes a value (result)Expensive calcValue (e.g., number, array)Avoid recalculating unless dependencies change
useCallbackMemoizes a functionStable functionFunctionPrevents passing new function on every render

✅ 1. React.memo(Component)

📌 Wraps a functional component and prevents re-render if props haven’t changed.

const MyComponent = React.memo(function MyComponent({ name }) {
  return <h2>{name}</h2>;
});

🧠 Use When:
You have a child component receiving unchanged props, but it re-renders anyway due to parent changes.

✅ 2. useMemo(() => compute(), [deps])

📌 Caches a computed value, and only recalculates it if its dependencies change.

const expensiveValue = useMemo(() => slowFunction(input), [input]);

🧠 Use When:

  • You’re doing a slow/expensive calculation
  • You want to avoid recalculating on every render

✅ 3. useCallback(() => fn, [deps])

📌 Caches a function so its reference doesn’t change unless dependencies change.

const handleClick = useCallback(() => {
  doSomething();
}, [dependency]);

🧠 Use When:

  • You pass a function to a child component (especially React.memo-wrapped)
  • You want to prevent useEffect in the child from running again

🧪 Visual Flow

Parent Re-renders ➜ 
 ├─ Child with new props/function ➜ child re-renders
 ├─ React.memo() + same props ➜ no re-render
 ├─ useMemo() ➜ reuses previous value
 └─ useCallback() ➜ reuses previous function

Keep Learning 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *