📖 Scenario: You are building a simple React app that counts clicks on two buttons. You want to make sure the click handler functions do not get recreated unnecessarily to keep your app efficient.
🎯 Goal: Build a React component with two buttons that share a click handler function memoized using the useCallback hook.
📋 What You'll Learn
Create a state variable count initialized to 0
Create a function handleClick that increases count by 1
Use the useCallback hook to memoize handleClick with count as dependency
Render two buttons that both use handleClick as their onClick handler
Display the current count value in a <p> tag
💡 Why This Matters
🌍 Real World
Using useCallback helps keep React apps fast by preventing unnecessary function recreations, especially when passing functions to child components.
💼 Career
Understanding useCallback is important for React developers to write efficient, maintainable code and improve app performance.
Progress0 / 4 steps
1
Set up state with useState
Import useState from React and create a state variable called count initialized to 0 inside a functional component named ClickCounter.
React
Hint
Use const [count, setCount] = useState(0); inside the component.
2
Create the click handler function
Inside the ClickCounter component, create a function called handleClick that calls setCount to increase count by 1.
React
Hint
Define handleClick as a function that calls setCount(count + 1).
3
Memoize the click handler with useCallback
Import useCallback from React and wrap the handleClick function with useCallback, passing count as a dependency.
Render two <button> elements inside the component. Both buttons should use handleClick as their onClick handler. Also render a <p> tag that shows the current count value.
React
Hint
Use JSX to render two buttons with onClick={handleClick} and a paragraph showing Count: {count}.
Practice
(1/5)
1. What is the main purpose of the useCallback hook in React?
easy
A. To memoize a function so it doesn't get recreated on every render unless dependencies change
B. To store a value that persists between renders
C. To fetch data from an API asynchronously
D. To create a new state variable
Solution
Step 1: Understand what useCallback does
useCallback returns a memoized version of a function that only changes if its dependencies change.
Step 2: Compare options with this behavior
Only To memoize a function so it doesn't get recreated on every render unless dependencies change describes memoizing a function to avoid recreating it unnecessarily.
Final Answer:
To memoize a function so it doesn't get recreated on every render unless dependencies change -> Option A
Quick Check:
useCallback = memoize function [OK]
Hint: Remember: useCallback memoizes functions to keep them stable [OK]
Common Mistakes:
Confusing useCallback with useState
Thinking useCallback stores values instead of functions
Assuming useCallback fetches data
2. Which of the following is the correct syntax to use useCallback in a React functional component?
easy
A. const memoizedFn = useCallback(doSomething(), [dependency]);
B. const memoizedFn = useCallback(() => { doSomething(); });
C. const memoizedFn = useCallback(() => { doSomething(); }, [dependency]);
D. const memoizedFn = useCallback(doSomething, dependency);
Solution
Step 1: Recall the correct useCallback signature
The hook takes a function and an array of dependencies: useCallback(fn, [deps]).
Step 2: Analyze each option
const memoizedFn = useCallback(() => { doSomething(); }, [dependency]); correctly passes an inline function and dependencies array. const memoizedFn = useCallback(() => { doSomething(); }); misses dependencies array. const memoizedFn = useCallback(doSomething(), [dependency]); calls doSomething() immediately, passing its return value instead of the function. const memoizedFn = useCallback(doSomething, dependency); passes dependency without array brackets, invalid.
What happens when the button is clicked multiple times quickly?
medium
A. The count increments correctly each time
B. The code throws an error because of missing dependencies
C. The count increments only once and then stops
D. The count increments but may lag behind due to stale closure
Solution
Step 1: Understand the closure inside useCallback
The increment function uses count from its dependencies. Because count is in the dependency array, the function updates when count changes, but rapid clicks may use a stale value.
Step 2: Analyze behavior on quick clicks
Rapid clicks may cause the function to use an outdated count value due to closure, causing increments to lag behind actual clicks.
Final Answer:
The count increments but may lag behind due to stale closure -> Option D
Quick Check:
useCallback with state dependency can cause stale closures [OK]
Hint: State in useCallback can be stale if updated rapidly [OK]
Common Mistakes:
Assuming count always updates instantly
Ignoring closure behavior in hooks
Thinking useCallback prevents all stale data issues
4. Identify the bug in this code using useCallback:
A. Missing dependency value in the dependency array causes stale state updates
B. Using useCallback without dependencies causes infinite re-renders
C. setValue should not be called inside useCallback
D. The function should not be memoized with useCallback
Solution
Step 1: Check the dependency array of useCallback
The callback uses value but the dependency array is empty, so the function never updates with new value.
Step 2: Understand the effect of missing dependencies
Because value is missing, the callback uses the initial value forever, causing stale increments.
Final Answer:
Missing dependency value in the dependency array causes stale state updates -> Option A
Quick Check:
Dependencies must include all used variables [OK]
Hint: Always include all variables used inside useCallback in dependencies [OK]
Common Mistakes:
Leaving dependency array empty when variables are used
Thinking setState functions need dependencies
Confusing useCallback with useMemo
5. You want to optimize a child component that receives a callback prop to avoid unnecessary re-renders. Which approach correctly uses useCallback to achieve this?
A. const handleClick = React.useCallback(() => setCount(count + 1), [count]);
B. const handleClick = React.useCallback(() => setCount(c => c + 1), []);
C. const handleClick = () => setCount(count + 1);
D. const handleClick = React.useCallback(() => setCount(count + 1));
Solution
Step 1: Understand the goal to avoid unnecessary re-renders
We want handleClick to be stable and not change unless needed, so the child doesn't re-render unnecessarily.
Step 2: Analyze each option's dependency array and function
const handleClick = React.useCallback(() => setCount(count + 1), [count]); depends on count, so it changes every time count changes, causing re-renders. const handleClick = React.useCallback(() => setCount(c => c + 1), []); uses functional update c => c + 1 and empty dependencies, so handleClick is stable. const handleClick = () => setCount(count + 1); recreates function every render. const handleClick = React.useCallback(() => setCount(count + 1)); misses dependencies array, which is invalid.
Final Answer:
const handleClick = React.useCallback(() => setCount(c => c + 1), []); -> Option B
Quick Check:
Stable callback with functional update and empty deps = const handleClick = React.useCallback(() => setCount(c => c + 1), []); [OK]
Hint: Use functional updates with empty deps to keep callback stable [OK]
Common Mistakes:
Including state in dependencies causing new functions each render
Not using functional updates when deps are empty
Omitting dependency array causing bugs
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.