JAVASCRIPT

Optimize React Performance with `useCallback` for Event Handlers

Optimize React performance with `useCallback`. Memoize event handler functions to prevent unnecessary re-renders of child components, significantly improving application speed.

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

// A child component that will only re-render if its props change
const Button = memo(({ onClick, label }) => {
  console.log(`Rendering Button: ${label}`);
  return (
    <button onClick={onClick} style={{ margin: '5px', padding: '10px', fontSize: '16px' }}>
      {label}
    </button>
  );
});

function CounterParent() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  const [someValue, setSomeValue] = useState(0);

  // Without useCallback, this function would be recreated on every CounterParent render,
  // causing ButtonOne to re-render even if its own state/props haven't changed.
  const incrementCount1 = useCallback(() => {
    setCount1(prevCount => prevCount + 1);
  }, []); // Empty dependency array: this function is created once and never changes.

  // This function depends on 'someValue', so it will only be recreated if 'someValue' changes.
  const incrementCount2 = useCallback(() => {
    setCount2(prevCount => prevCount + someValue);
  }, [someValue]); // Dependency array: recreate if someValue changes.

  console.log('Rendering CounterParent');

  return (
    <div style={{ padding: '20px', border: '1px solid #eee', borderRadius: '8px', maxWidth: '600px', margin: '20px auto', textAlign: 'center' }}>
      <h1>useCallback Demo</h1>
      <p>Count 1: {count1}</p>
      <Button onClick={incrementCount1} label="Increment Count 1" />

      <p>Count 2: {count2} (increments by {someValue})</p>
      <Button onClick={incrementCount2} label="Increment Count 2" />

      <p>Some Value: {someValue}</p>
      <button
            onClick={() => setSomeValue(prev => prev + 1)}
            style={{ margin: '5px', padding: '10px', fontSize: '16px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '5px' }}
          >
            Change Some Value
          </button>
          <p>Open console to observe 'Rendering Button' logs.</p>
          <p>Notice how 'Increment Count 1' button only renders once, while 'Increment Count 2' re-renders when 'Some Value' changes.</p>
        </div>
      );
    }

    export default CounterParent;
How it works: This snippet demonstrates `useCallback` for optimizing performance by preventing unnecessary re-creation of functions. When `CounterParent` re-renders, functions defined within it are normally re-created. By wrapping `incrementCount1` and `incrementCount2` with `useCallback`, these functions are memoized. `Button` is also wrapped in `memo` to ensure it only re-renders if its props (`onClick` or `label`) actually change. `incrementCount1` is memoized with an empty dependency array, meaning it's created once. `incrementCount2` has `someValue` in its dependency array, so it's re-created only when `someValue` changes, showcasing conditional memoization.

Need help integrating this into your project?

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

Hire DigitalCodeLabs