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.