React Memoization

Optimize your React components with memoization techniques

🚀 What is React Memoization?

Memoization is a performance optimization technique that caches component results to prevent unnecessary re-renders. It helps React apps run faster by remembering previous computations and reusing them when inputs haven't changed.


import React, { memo } from 'react';

// Memoized component - only re-renders when props change
const ExpensiveComponent = memo(({ data }) => {
  return <div>{data}</div>;
});
                                    

Result:

Component only re-renders when 'data' prop changes, not when parent re-renders.

Memoization Techniques

⚛️

React.memo()

Memoizes entire components

const MyComponent = memo((props) => {
  return <div>{props.name}</div>;
});
🎣

useMemo()

Memoizes computed values

const result = useMemo(() => {
  return expensiveCalculation(a, b);
}, [a, b]);
🔧

useCallback()

Memoizes function references

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

Performance

Reduces unnecessary renders

// Prevents child re-renders
<MemoizedChild data={data} />

🔹 Using React.memo()

React.memo() is a higher-order component that prevents re-renders when props haven't changed. It's perfect for components that render often with the same props.

import React, { memo, useState } from 'react';

// Without memo - re-renders every time parent updates
const RegularChild = ({ name }) => {
  console.log('RegularChild rendered');
  return <div>Hello {name}</div>;
};

// With memo - only re-renders when 'name' changes
const MemoizedChild = memo(({ name }) => {
  console.log('MemoizedChild rendered');
  return <div>Hello {name}</div>;
});

function Parent() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('John');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Count: {count}
      </button>
      <MemoizedChild name={name} />
    </div>
  );
}

Output:

MemoizedChild only re-renders when 'name' changes, not when 'count' changes.

🔹 Using useMemo()

useMemo() caches the result of expensive calculations. It only recalculates when dependencies change, saving processing time on every render.

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

function ExpensiveCalculation() {
  const [count, setCount] = useState(0);
  const [items, setItems] = useState([1, 2, 3, 4, 5]);

  // Without useMemo - calculates on every render
  // const total = items.reduce((sum, item) => sum + item, 0);

  // With useMemo - only calculates when 'items' changes
  const total = useMemo(() => {
    console.log('Calculating total...');
    return items.reduce((sum, item) => sum + item, 0);
  }, [items]);

  return (
    <div>
      <p>Total: {total}</p>
      <button onClick={() => setCount(count + 1)}>
        Count: {count}
      </button>
    </div>
  );
}

Output:

Total: 15

Calculation only runs when 'items' array changes, not on every button click.

🔹 Using useCallback()

useCallback() memoizes function references to prevent child components from re-rendering. It's useful when passing callbacks to optimized child components that rely on reference equality.

import React, { useState, useCallback, memo } from 'react';

const Button = memo(({ onClick, children }) => {
  console.log('Button rendered:', children);
  return <button onClick={onClick}>{children}</button>;
});

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

  // Without useCallback - new function on every render
  // const handleClick = () => setCount(count + 1);

  // With useCallback - same function reference
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={handleClick}>Increment</Button>
      <button onClick={() => setOtherState(otherState + 1)}>
        Other: {otherState}
      </button>
    </div>
  );
}

Output:

Memoized Button doesn't re-render when 'otherState' changes.

🔹 When to Use Memoization

Memoization isn't always necessary. Use it strategically for better performance:

✅ Good Use Cases:

  • Components that render frequently with same props
  • Expensive calculations or data transformations
  • Large lists or complex component trees
  • Passing callbacks to memoized child components

❌ Avoid When:

  • Props change frequently anyway
  • Component is already fast
  • Simple calculations or small components
  • Premature optimization without measuring
// Good: Expensive list filtering
const filteredList = useMemo(() => {
  return largeArray.filter(item => item.active);
}, [largeArray]);

// Bad: Simple addition (overhead not worth it)
const sum = useMemo(() => a + b, [a, b]);

🧠 Test Your Knowledge

Which hook memoizes function references?