JAVASCRIPT

Optimize Component Performance with useCallback

Understand how to use React's useCallback hook to memoize event handler functions, preventing unnecessary re-renders of child components and improving application performance.

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

// A simple child component that re-renders if its props change
const Button = React.memo(({ onClick, label }) => {
  console.log(`Rendering Button: ${label}`);
  return <button onClick={onClick}>{label}</button>;
});

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

  // This function reference changes on every render of ParentComponent
  const handleClickWithoutCallback = () => {
    setCount(prevCount => prevCount + 1);
  };

  // This function reference is stable unless 'count' changes
  // (in this specific example, 'count' is not used inside, so it could be [])
  // We use useCallback to memoize the function reference.
  const handleClickWithCallback = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // Empty dependency array means this callback is memoized once and never changes.

  const handleOtherStateChange = useCallback(() => {
    setOtherState(prev => prev + 1);
  }, []);

  console.log('Rendering ParentComponent');

  return (
    <div>
      <h1>useCallback for Performance</h1>
      <p>Count: {count}</p>
      <p>Other State: {otherState}</p>

      <h2>Without useCallback:</h2>
      {/* This button will re-render even if its label and the logic of handleClickWithoutCallback haven't changed, because a new function reference is created on every ParentComponent render. */}
      <Button onClick={handleClickWithoutCallback} label="Increment Count (No Callback)" />

      <h2>With useCallback:</h2>
      {/* This button will only re-render if its props (onClick in this case) actually change. Since handleClickWithCallback is memoized, the Button component (wrapped in React.memo) avoids unnecessary re-renders. */}
      <Button onClick={handleClickWithCallback} label="Increment Count (With Callback)" />

      <button onClick={() => setOtherState(otherState + 1)} style={{marginTop: '20px'}}>
        Change Other State (Triggers Parent re-render)
      </button>
    </div>
  );
}

export default ParentComponent;
How it works: The `useCallback` hook is a performance optimization tool in React. It memoizes a function definition, preventing it from being re-created on every render unless its dependencies change. In this example, `handleClickWithCallback` is memoized with an empty dependency array, ensuring its reference remains stable. When passed to `React.memo`-wrapped child components like `Button`, this stable reference prevents the child from re-rendering unnecessarily when the parent component re-renders but the callback's logic or dependencies haven't changed, thus improving application performance by reducing rendering overhead.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs