Skip to content

React useCallback Interview Guide

useCallback is a React Hook that memoizes a function and returns the same function instance between renders unless its dependencies change.

const memoizedFn = useCallback(() => {
console.log("Hello");
}, []);

Why?

To prevent unnecessary recreation of functions and avoid unwanted child component re-renders.


Normally, functions are recreated on every render.

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

Every render creates a new function reference.

useCallback preserves the same function reference.

const handleClick = useCallback(() => {
console.log("Clicked");
}, []);

Useful when passing functions to memoized child components.

flowchart TD
    A[Component Renders] --> B{Dependencies Changed?}
    B -->|No| C[Return Existing Function Reference]
    B -->|Yes| D[Create New Function]
    D --> E[Store New Function & Dependencies]
    C --> F[Pass Stable Reference]
    E --> F

Internally React stores:

{
callback: functionRef,
dependencies: [...]
}

On every render React compares the dependency array.

  • Same dependencies -> returns the previous function.
  • Changed dependencies -> creates and stores a new function.

useCallback useMemo
Memoizes a function Memoizes a value
Returns a function Returns computed value
Used for callbacks/event handlers Used for expensive computations
const calculate = useMemo(() => a + b, [a, b]);
const handleClick = useCallback(() => {
console.log(a);
}, [a]);

Use it when:

  • Passing callbacks to components wrapped with React.memo
  • A callback appears in another Hook’s dependency array
  • Avoiding unnecessary child re-renders

Avoid using it everywhere.


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

Whenever count changes, React creates a new callback.


Yes, but only in appropriate scenarios.

const Child = React.memo(({ onClick }) => {
console.log("Child Rendered");
return <button onClick={onClick}>Click</button>;
});
const handleClick = useCallback(() => {
console.log("Clicked");
}, []);

Without useCallback, a new function reference is passed every render, causing React.memo to re-render the child.

Yes.

React must:

  • Store callback
  • Store dependencies
  • Compare dependencies

For simple components, this overhead may outweigh any benefit.


Incorrect:

const [count, setCount] = useState(0);
const showCount = useCallback(() => {
console.log(count);
}, []);

Output always:

0

Correct:

const showCount = useCallback(() => {
console.log(count);
}, [count]);

Without useCallback:

<Child onClick={() => console.log("Click")} />

Each render creates a new function.

oldFn !== newFn

React.memo detects changed props and re-renders.

With useCallback:

const handleClick = useCallback(() => {
console.log("Click");
}, []);
<Child onClick={handleClick} />

Function reference remains stable.


const fn1 = () => {};
const fn2 = () => {};
console.log(fn1 === fn2); // false

Different functions occupy different memory references.

With useCallback:

const fn = useCallback(() => {}, []);

The same reference is reused until dependencies change.


Does useCallback Prevent Component Re-renders?

Section titled “Does useCallback Prevent Component Re-renders?”

No.

It only memoizes the function.

Components still re-render when:

  • State changes
  • Props change
  • Context changes

Incorrect:

const fetchData = () => {};
useEffect(() => {
fetchData();
}, [fetchData]);

This causes repeated executions because fetchData changes every render.

Correct:

const fetchData = useCallback(() => {
// API call
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);

Normal:

const handleClick = () => {};

Memoized:

const handleClick = useCallback(() => {}, []);

  • Small components
  • Functions not passed as props
  • No measurable performance issue
  • Premature optimization

An e-commerce application contains:

  • Product list
  • Filters
  • Sorting
  • Search

Each product card is wrapped in React.memo.

Without useCallback, filter and sort handlers are recreated on every keystroke, causing every product card to re-render.

Using useCallback stabilizes handler references, reducing unnecessary renders.

Why Doesn’t It Always Improve Performance?

Section titled “Why Doesn’t It Always Improve Performance?”

Because React must:

  • Store callbacks
  • Store dependency arrays
  • Compare dependencies

If callback creation is cheaper than memoization, performance may decrease.

React compares callback props by reference.

prevProps.onClick === nextProps.onClick

If equal:

  • React.memo skips rendering.

Otherwise:

  • Child re-renders.

Useful tools:

  1. React DevTools Profiler
  2. Why Did You Render
  3. Console logging
console.log("Child rendered");

useCallback memoizes the function reference, not the captured values.

Always specify correct dependencies to avoid stale closures.


Question Answer
Purpose Memoize function
Returns Function
Dependency changes New function created
Primary use case Prevent child re-renders
Works well with React.memo
Similar hook useMemo
Prevents component render? No
Can hurt performance? Yes
Common issue Stale closure

useCallback memoizes a function reference between renders. It is primarily used with React.memo or dependency-based hooks to avoid unnecessary function recreation and child component re-renders.

  • useCallback memoizes function references, not computed values.
  • It is most beneficial when used with React.memo or Hook dependency arrays.
  • Incorrect dependency arrays can lead to stale closures.
  • Overusing useCallback may reduce performance due to memoization overhead.
  • Profile performance before introducing memoization optimizations.