React project demonstrating the use of
useMemoandReact.memo, as well asuseCallbackfor performance optimization.
- Default Rendering Behavior
- Overview of Optimizations
- Key Differences
- Understanding Memoization
- Understanding Shallow Comparison
- Basic Syntax of useMemo
- Basic Syntax of useCallback
- Basic Syntax of React.memo
- Changes to Default Rendering Behavior
- Project Structure
By default, React will re-render a component when:
- Its state changes → When you call
setState, the component and its children re-render. - Its props change → If a parent component passes new props, the child component re-renders.
- Its parent re-renders → If a parent component re-renders (even without changing props), React re-renders its children.
This default re-rendering behavior ensures that the UI stays in sync with the application state, but this often leads to unnecessary re-renders that negatively impact performance.
That is where useMemo, useCallback, and React.memo come into place. These optimizations, provided by React, help reduce unnecessary re-renders and improve application performance.
The useMemo React Hook is used to optimize performance by memoizing (also known as caching) the result of a function or computation, so that it is only recalculated when its dependencies change. This prevents expensive computations from running unnecessarily during every render.
Tip
Check out the complete React documentation on the built-in useMemo hook.
In React, React.memo is a higher-order component (HOC) provided by React, specifically designed to automatically memoize functional components. When a component is wrapped with React.memo, it will re-render only if its props have changed.
useCallback is a React Hook used to memoize callback functions. It ensures that a function reference remains the same across renders unless its dependencies change.
This optimization is useful when passing callbacks to child components to prevent re-creations of functions during component re-renders.
If you pass a new function reference (even with the same logic) as a prop, React.memo will trigger a re-render. useCallback ensures that the function reference stays the same across renders, working effectively with React.memo.
Tip
Check out the complete React documentation on the built-in useCallback hook.
| Feature | React.memo |
useMemo |
useCallback |
|---|---|---|---|
| Functionality | Prevents a component from re-rendering based on its props. | Caches the result of a function call based on its dependencies. | Caches a function definition so it does not get re-created on every render. |
| Usage | Used to wrap a functional component. | Called inside a functional component to memoize a specific calculation. | Wraps a function inside a functional component. |
| Comparison | Performs a shallow comparison of props by default to determine if a re-render is needed. | Explicitly defines dependencies in an array to control when the calculation is re-run. | Explicitly defines dependencies in an array to determine when the function should be re-created. |
React.memo focuses on optimizing component rendering, while useMemo optimizes specific calculations within a component.
Use Case for Each:
- Use
React.memowhen you have a component that is rendered frequently and its rendering logic is relatively simple but depends heavily on its props. - Use
useMemowhen you have a computationally expensive calculation within a component that needs to be cached and only re-calculated when its dependencies change. - Use
useCallback:- When functions are passed as props, preventing unnecessary child re-renders.
- When passing functions as props to child components wrapped with
React.memo. - When functions are used as dependencies in
useEffectoruseMemoto avoid triggering unintended re-runs.
Caching is a technique that allows us to store a copy of a given resource and serve it back when it is requested.
Memoization is a technique used to optimize the performance of functions by caching the results of expensive function calls and reusing them when the same inputs occur again.
In React applications, memoization helps avoid redundant rendering of components, ultimately leading to a smoother user experience.
Shallow comparison refers to a comparison of references only, not the actual content of the objects. If two variables reference the same object in memory, the shallow comparison will consider them equal. It does not go into nested objects or arrays to check for equality.
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
const array3 = array1; // Points to the same memory reference as array1
console.log(array1 === array2); // false (different references)
console.log(array1 === array3); // true (same reference)const cachedValue = useMemo(calculateValue, dependencies)calculateValue: The function calculating the value that you want to cache.- React will call this function during the initial render.
- On next renders, React will return the same value if the
dependencieshave not changed.
dependencies:- List of all reactive values referenced inside of the calculateValue code.
- This include props, state, and all the variables and functions declared directly inside your component body.
const memoizedCallback = useCallback(
() => {
// Callback Function (Your callback logic here)
},
[dependencies] // Dependency Array (function recreation if these change)
);- Callback Function - The function you want to memoize.
- Dependency Array - Determines when the memoized function should be recreated.
- A memoized version of the function that only changes if the dependencies change will be returned.
There are multiple ways to use React.memo, here are a few examples:
Example 1:
The React.memo function is used to wrap the component and then export:
import React from 'react';
const ComponentOne = (props) => {
/* component code */
};
export default React.memo(ComponentOne);Example 2:
The memo() function is used to wrap a new variable and then store the memoized component to be exported:
import { memo } from "react";
const ComponentTwo = (props) => {
/* render using props */
};
export const MemoComponent = memo(ComponentTwo);Example 3:
The memo() function is used to wrap the entire component:
import { memo } from "react";
const ComponentThree = memo((props) => {
/* component code */
});
export default ComponentThree;| Feature | Default Behavior | React.memo |
useMemo |
useCallback |
|---|---|---|---|---|
| State Change | Component always re-renders | No effect | No effect | No effect |
| Props Are the Same | Component re-renders | ✅ Prevents re-render | No effect | No effect |
| Parent Re-renders | Child re-renders | ✅ Prevents re-render | No effect | No effect |
| Expensive Computations | Always recalculates | No effect | ✅ Prevents recalculation | No effect |
| Functions as Props | New function created on every render | No effect | No effect | ✅ Prevents re-creation |
performance-optimization/
├── public/
├── index.html
├── favicon.ico
├── manifest.json
└── robots.txt
├── src/
├── components/
| ├── Demo/
| | ├── DemoList.js
| | ├── DemoList.module.css
| ├── UI/
| | ├── Button/
| | | ├── Button.js
| | | ├── Button.module.css
├── App.css
├── App.js
├── index.css
├── index.js
├── .gitignore
├── package.json
├── readme.md