React Hooks - useCallback

| 4 min read

What is useCallback?

The hook allows you to cache a function definition and optimize the performance of your component by only re-rendering if one of its dependencies has changed. This hook works similarly to useMemo, but to memorize function instead.

The hook takes 2 parameters: function, and dependencies.

  • function - the value of the function that you want to cache or remember
  • dependencies - this is to tell the hook to re-run when one of the dependenciesā€™ values changed

Imagine you have a toolbox containing a hammer, a screwdriver, and a wrench that are all in brand-new condition. The toolbox represents the useCallback hook, which keeps track of the condition of these tools. Every time you use a tool, its condition slowly degrades, but you donā€™t have to replace the tool right away. For example, you used the hammer many times and it is wearing out faster than the other 2 tools. One day, you replaced the old and worn-out hammer with a brand-new hammer. This is when the toolbox will ā€œre-renderā€ because the hammer dependency is changed. This is similar to how a component will only re-render if one of its dependencies has changed, as determined by the useCallback hook.

Why React re-render?

React re-renders whenever its state or value changes. Remember how JavaScrip evaluates equals for string, number, array, object, and function? As long as, the state or value reminds the same, re-render should not happen, however, that is not the case for arrays, objects, and functions.

See the function example below, both functions return the same value hi, but when you use triple equals and get a false result. The useCallback hook is to remember the value from the function and then both functions will be the ā€œsameā€.

console.log("Number comparsion", 1 === 1); // true
console.log("String comparsion", "hi" === "hi"); // true
console.log("Array comparsion", [] === []); // false
console.log("Object comparsion", {} === {}); // false

function ff1() {
	return "hi";
}

function ff2() {
	return "hi";
}

console.log("Function comparion", ff1 === ff2); // false

The difference between with and without useCallback

Without useCallback

As you can see, I typed hello (5 letters) and the console shows it logged the same thing 5 times. This tells us that the app was re-rendered 5 times.

the console log will log 5 times as you type hello without useCallback

With useCallback

Letā€™s add useCallback hook. I typed hello like I did before and the console doesnā€™t show any logged value. This is because useCallback hook knows the function value is the same as before, therefore, the app did not re-render.

the console log doesn't log anything as you type with useCallback

Test Code

I borrowed partial code from Dave Grayā€™s video and I listed it as one of the resources below.

function App() {
	const [userInput, setUserInput] = useState("");
	const [num1] = useState(4);
	const [num2] = useState(5);

	const sum = () => num1 + num2;
	// const sum = useCallback(() => num1 + num2, [num1, num2]);

	useEffect(() => {
		console.log(`New sum value: ${sum()}`);
	}, [sum]);

	return (
		<main className="App">
			<input
				type="text"
				placeholder="input"
				value={userInput}
				onChange={(e) => setUserInput(e.target.value)}
			/>
			<h2>Output: {userInput || "--"}</h2>
			<h2>Sum: {sum()}</h2>
		</main>
	);
}

Recap

The useCallback hook and the useMemo hook have similar functionality in preventing unnecessary re-renders and improving the performance of React apps. However, itā€™s not necessary to wrap all functions with useCallback and it depends on the app structure and the specific use case. A good practice is to use React DevTools to inspect which components are causing performance issues, and then determine if useCallback or useMemo would be an appropriate solution in those cases.

Resources

Thank you!

Thank you for your time and for reading this!