React Optimization Techniques: The Essential Trio of memo, useMemo, and useCallback - Surekha Technologies
React Optimization Techniques: The Essential Trio of memo, useMemo, and useCallback

When building React applications, performance is a top priority. A smooth user experience can be heavily impacted by unnecessary re-renders, which can slow down your app. React offers several powerful tools: React.memo, useMemo, and useCallback to help optimize performance by preventing unnecessary updates and reducing the computational load. In this post, we’ll explore these tools in depth, explain their use cases, and provide examples that will help you use them effectively.
What Are These Tools?
- React.memo : React.memo allows you to wrap functional components, so they only re-render when their props change. This helps to improve performance by reducing unnecessary re-renders.
- useMemo : A hook that memoizes a computed value, ensuring that it’s only recalculated when its dependencies change. It's particularly useful when dealing with non-primitive data types, such as arrays or objects.
- useCallback : useCallback is a React hook that memoizes a function, ensuring that the function reference doesn’t change unless its dependencies change. This is particularly useful when passing functions down to memoized child components.
When to Use Each Tool
1. React.memo
Use Case: React.memo is especially useful in a parent-child relationship, where the parent component may update its state, but you want to ensure that the child component only re-renders when its specific props change. This optimizes performance by minimizing renders when the child component’s props remain the same.
Example:
import React from "react"; const ChildComponent = React.memo(({ count }) => { console.log("Child rendered"); return <div>Count: {count}</div>; }); const ParentComponent = () => { const [count, setCount] = React.useState(0); const [text, setText] = React.useState(""); return ( <div> <ChildComponent count={count} /> <input value={text} onChange={(e) => setText(e.target.value)} /> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default ParentComponent;
In this example, ChildComponent will only re-render when the count prop changes. If you add more components or props, React.memo can help reduce re-renders, improving performance.
Never use React.memo for components that always need to re-render or those with zero props. For example, memoization adds unnecessary complexity for the ChildComponent which does not rely on props and simply displays static content.
2. useMemo
Use Case: Use useMemo when you have an expensive computation involving non-primitive data types (like arrays or objects) that should only run when specific values change. This hook ensures that the calculation is only performed when its dependencies change, eliminating unnecessary recalculations and improving efficiency for complicated data structures.
Example:
import React, { useState, useMemo } from "react"; const ExpensiveComponent = ({ items }) => { const total = useMemo(() => { console.log("Calculating total..."); return items.reduce((sum, item) => sum + item, 0); }, [items]); return <div>Total: {total}</div>; }; const UseMemoExample = () => { const [count, setCount] = useState(0); const items = [1, 2, 3, 4, 8]; return ( <div> <ExpensiveComponent items={items} /> <button onClick={() => setCount(count + 1)}>Increment: {count}</button> </div> ); }; export default UseMemoExample;
Here, the total is recalculated only when items change, not on every render of the App component. This is useful for preventing unnecessary calculations.
UseMemo may be overkill for quick and easy computations, like as adding two numbers. It does not improve performance; instead, it increases complexity.
3. useCallback
Use Case: Use useCallback when you need to pass functions as props to memoized components. To avoid unnecessary re-renders, this is crucial for performance optimisation in cases when the child component depends on the same function reference. This hook keeps the function reference consistent between renderings, preventing the function from being rebuilt every time the parent component renders.
Example:
const Button = React.memo(({ onClick, label }) => { console.log(`Rendering button: ${label}`); return <button onClick={onClick}>{label}</button>; }); const ParentComponent = () => { const [count, setCount] = React.useState(0); const handleClick = useCallback(() => { console.log('Button clicked'); }, []); return ( <div> <Button onClick={handleClick} label="Click Me!" /> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); };
In above example, handleClick will maintain the same reference across renders. This is particularly important when passing it to the Button, which is wrapped in React.memo.
If the function doesn’t depend on any props or state, or if it’s a simple inline function, you may not need to use useCallback.
Example of Combined use of memo, useMemo and useCallback:
const Item = () => { console.log("Item re-render"); return <div>Item</div>; }; const Page = ({ onClick, value }) => { console.log("Page re-render"); return ( <> Page <Item /> <> ); }; const PageMemo = React.memo(Page); const App = () => { const [state, setState] = useState(1); const onClick = useCallback(() => { console.log("do something on click"); }, []); const value = useMemo(() => [1, 2, 3], []); return ( <div className="App"> <button onClick={() => setState(state + 1)}> click to re-render {state} </button> <br /> <PageMemo onClick={onClick} value={value} /> </div> ); };
This example demonstrates how React.memo, useCallback, and useMemo work together to optimize rendering. The PageMemo component only re-renders when its props change, while the Item component remains unaffected by state changes in the App component. This setup improves performance by preventing unnecessary re-renders.
Summary
Use React.memo for components that receive props and should avoid unnecessary re-renders.
Use useMemo for expensive calculations, especially when dealing with non-primitive data types, to ensure recalculation only occurs when dependencies change.
Use useCallback for functions that are passed to memoized components, ensuring the function reference remains stable.
Conclusion
Optimizing React applications is crucial for improving performance, user experience, and scalability. Techniques like memoization using memo, useMemo, and useCallback play a vital role in reducing unnecessary re-renders and enhancing speed. However, it’s essential to avoid overusing these tools, as they can complicate your code without providing real benefits. These tools help ensure that your React apps run smoothly, even as complexity grows.
At Surekha Technologies, we specialize in ReactJS development services, leveraging these optimization techniques to deliver high-performance, scalable web applications. Whether you're building a new project or enhancing an existing one, our team of experts can help you implement the best practices in React development.
Find out how our ReactJS application development expertise can benefit your business. For more details Contact us !
For Your Business Requirements
2 - 4 October 2024
Hall: 10, Booth: #B8 Brussels, Belgium