React useCallback Hook

The useCallback hook is used to memoize a function in React. It ensures that a function reference does not change unless its dependencies change. This is particularly useful when passing functions as props to child components, as it prevents unnecessary re-renders and optimises performance.


1. Basic Example: Avoiding Re-Creation of Functions using useCallback Hook

In this example, we use useCallback to memoize a button click handler. Without useCallback, the handler function would be recreated on every render, which could lead to performance issues in larger applications.

App.js

</>
Copy
import React, { useState, useCallback } from 'react';

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

  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // No dependencies, so function is memoized forever

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

Explanation:

  • useCallback: Memoizes the increment function to prevent it from being recreated on every render.
  • The empty dependency array [] ensures that the function is created only once and reused thereafter.
  • This is useful for preventing performance issues when the function is passed as a prop to child components.

Output:


2. Example: Optimising Child Component Re-Renders using useCallback Hook

In this example, we demonstrate how useCallback prevents unnecessary re-renders of child components by memoizing the functions passed as props. The child component will only re-render if the function reference changes.

App.js

</>
Copy
import React, { useState, useCallback, memo } from 'react';

const Child = memo(({ onClick }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Click Me</button>;
});

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

  const handleClick = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // Memoize the function

  return (
    <div>
      <h2>Parent Count: {count}</h2>
      <Child onClick={handleClick} />
    </div>
  );
}

export default Parent;

Explanation:

  • memo: Wraps the child component to prevent unnecessary re-renders unless its props change.
  • useCallback: Ensures the handleClick function reference remains the same between renders.
  • The child component only re-renders when the handleClick function reference changes, optimizing performance.

Output:


3. Example: Dependency Management using useCallback Hook

In this example, we use dependencies in useCallback to update the memoized function when certain state variables change. This ensures the function remains consistent with the latest state.

App.js

</>
Copy
import React, { useState, useCallback } from 'react';

function Greeting() {
  const [name, setName] = useState('');
  const [greeting, setGreeting] = useState('');

  const updateGreeting = useCallback(() => {
    setGreeting(`Hello, ${name}!`);
  }, [name]); // Dependency array includes 'name'

  return (
    <div>
      <input
        type="text"
        value={name}
        onChange={e => setName(e.target.value)}
        placeholder="Enter your name"
      />
      <button onClick={updateGreeting}>Update Greeting</button>
      <p>{greeting}</p>
    </div>
  );
}

export default Greeting;

Explanation:

  • useCallback: Memoizes the updateGreeting function and re-creates it only when name changes.
  • The dependency array ensures the function always uses the latest value of name.
  • This approach keeps the function optimized while ensuring it behaves correctly with updated state.

Output:


Conclusion

The useCallback hook is a powerful tool for optimising performance in React applications. By memoizing functions, you can prevent unnecessary re-renders and improve the efficiency of components that rely on function props. Use useCallback when passing functions as props or when a function depends on specific state variables.