DEV Community

Cover image for React.memo + useCallback: How to avoid unnecessary re-renders
Gunnar Halen
Gunnar Halen

Posted on

2

React.memo + useCallback: How to avoid unnecessary re-renders

When working with React, it's common to run into performance issues caused by unnecessary component re-renders. This usually happens when child components are being re-rendered even if their props haven't changed.

Luckily, React gives us two simple tools to optimize this: React.memo and useCallback.

In this post, I'll explain how they work and when to use them — with practical examples.


✅ The Problem: Too many re-renders

Imagine you have a parent component that updates state frequently, and a child component that receives a prop (like a callback function). Even if the child doesn't need to re-render, it will — because the function prop is re-created on every render.

Here’s a simplified version of that scenario:

import { useState } from 'react';

function MyButton({ onClick }: { onClick: () => void }) {
  console.log('Button rendered');
  return <button onClick={onClick}>Click me</button>;
}

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

  const handleClick = () => {
    console.log('Clicked');
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <MyButton onClick={handleClick} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Even if handleClick doesn’t change, it’s recreated on every render — causing MyButton to re-render too.


💡 The Solution: React.memo + useCallback

React.memo

React.memo is a higher-order component that memoizes a component, preventing unnecessary re-renders if the props haven't changed.

const MyButton = React.memo(({ onClick }: { onClick: () => void }) => {
  console.log('Button rendered');
  return <button onClick={onClick}>Click me</button>;
});
Enter fullscreen mode Exit fullscreen mode

But this alone isn't enough — if you're passing a new function on every render, it still counts as a new prop.


useCallback

That's where useCallback comes in. It memoizes the function itself, so its reference only changes when its dependencies change.

const handleClick = useCallback(() => {
  console.log('Clicked');
}, []); // empty deps = function is stable
Enter fullscreen mode Exit fullscreen mode

Together, these two tools ensure that MyButton won't re-render unless it actually needs to.


🔧 Full Example

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

const MyButton = React.memo(({ onClick }: { onClick: () => void }) => {
  console.log('Button rendered');
  return <button onClick={onClick}>Click me</button>;
});

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

  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <MyButton onClick={handleClick} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

✅ Now MyButton only renders once unless handleClick or other props change.


🧠 When to use (and when not to)

  • Use React.memo when your component:

    • Receives stable props (like functions or values that rarely change).
    • Is pure and doesn't depend on external state.
    • Is relatively expensive to render.
  • Use useCallback when:

    • You're passing functions as props to memoized children.
    • You want to keep a stable function reference between renders.

⚠️ Avoid overusing these tools — they add some complexity. Use them when profiling shows re-renders are hurting performance.


🚀 Final Thoughts

React.memo and useCallback are powerful tools to improve performance and avoid unnecessary rendering. Together, they help keep your app efficient and responsive.

Have you used React.memo or useCallback in your projects?

Let me know how — or if you’ve run into any gotchas! 👇


🔗 Follow me for more practical React + TypeScript tips!

Image of Datadog

How to Diagram Your Cloud Architecture

Cloud architecture diagrams provide critical visibility into the resources in your environment and how they’re connected. In our latest eBook, AWS Solution Architects Jason Mimick and James Wenzel walk through best practices on how to build effective and professional diagrams.

Download the Free eBook

Top comments (0)

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay