Skip to main content

Memoization

In React, whenever a parent component updates its state, all of its child components automatically re-render by default. This is usually very fast. However, if a child component handles massive Data Tables or complex SVG charts, rendering it repeatedly can cause visible lag.

Memoization is an optimization technique that speeds up applications by storing the results of expensive function calls and returning the cached result when the inputs match.

1. React.memo for Components

You can wrap a component block in React.memo to tell React not to re-render the child component unless its specific props have changed.

import { memo } from 'react';

// This component will ONLY re-render if 'title' or 'data' changes.
const HeavyChart = memo(function HeavyChart({ title, data }) {
return <div>{/* Complex UI logic rendered here */}</div>;
});

export default HeavyChart;

2. useMemo for Calculations

Sometimes, you have a function that computes a difficult formula inside the component. You can use the useMemo hook to cache the result of that formula.

It takes a formula function and a dependency array. It will only recalculate the formula if the dependency numbers change.

import { useMemo, useState } from 'react';

export default function ExpensiveCalculator({ numbers }) {
const [theme, setTheme] = useState('light');

// If the user just clicks 'setTheme', this calculation is skipped!
const total = useMemo(() => {
console.log("Calculating massive numbers...");
return numbers.reduce((acc, num) => acc + num, 0);
}, [numbers]);

return (
<div className={theme}>
Total: {total}
<button onClick={() => setTheme('dark')}>Toggle Theme</button>
</div>
);
}

3. useCallback for Functions

Whenever a component re-renders, any functions defined inside it are entirely recreated in memory as brand new objects. If you pass a newly created function down to a child component wrapped in React.memo, the child will assume the prop changed and re-render anyway, defeating the purpose of the memo tracking.

useCallback caches the actual function definition between renders.

import { useCallback, useState } from 'react';
import SearchBar from './SearchBar';

export default function SearchPage() {
const [query, setQuery] = useState('');

// Ensures this exact function reference is maintained across renders
const handleSearch = useCallback((term) => {
console.log("Searching for", term);
}, []);

return <SearchBar onSearch={handleSearch} />;
}