Learn

React provides us with one more memoization function: useCallback(). Again, React will recreate all code defined inside a component when it is re-rendered, including functions. useCallback() allows us to memoize a function, preventing React from recreating that function when the component re-renders.

This hook is particularly important when passing functions as props to components memoized with React.memo(). Since React.memo() compares props between renders, it checks if each prop is the same before and after each render. The problem is that in JavaScript, two identical functions will not equal each other since they are stored in the language as two separate references. Here’s an example:

const exampleA = () => { console.log('example') } const exampleB = () => { console.log('example') } exampleA === exampleB // false

The code sample above will return false, even though the exampleA and exampleB are functionally equivalent.

Consider a parent component that creates a function and passes it as a prop to a memoized child component. If the parent component re-renders, it will recreate the function and pass it along to the child. Despite being functionally equivalent, the memoized child component will not be able to see that the old function and the new function are equivalent and will have no choice but to re-render unnecessarily.

To solve this, we can use the useCallback() hook, which accepts two arguments. The first argument is the function we want to memoize and the second is a list of dependencies. The useCallback() hook will only recreate the function if its list of dependencies changes. Similar to useEffect(), if an empty dependency array is passed to useCallback(), the function will only be created once after the first render.

Here’s an example to demonstrate its syntax:

import { useState, useCallback } from 'react'; import MemoizedCounter from './Counter.js'; const CounterContainer = () => { const [count, setCount] = useState(0); const increment = useCallback(() => setCount((count) => count + 1), []); return <MemoizedCounter onClick={increment} /> }

In this example, React will only recreate the increment() function when its list of dependencies change. This is important, because if <MemoizedCounter> is wrapped with React.memo(), it will compare the onClick prop before and after each render to see if <MemoizedCounter /> should be re-rendered. Since useCallback() will persist the increment() function on between render phases, <MemoizedCounter /> will only render on mount.

Instructions

Task 1

Go to the project’s home page (/), and then click on “Exercise 4: Memoizing Functions”.


Task 2

This exercise is similar to the previous exercise, however <GraphPoint /> is already wrapped in React.memo(). Open the React profiler and click the “Show Explainers” button. Notice that each <GraphPoint /> re-renders on every click. Let’s find out why.


Task 3

Open ./src/pages/Exercise4/index.js. In this component, we create a function named setGraphPointOn(), then we pass it to <GraphPoint /> as a prop. Why might changing the state of showExplainer in <Exercise4 /> cause <GraphPoint /> to re-render?

Hint

Every time showExplainer is updated, React will recreate the setGraphPointOn() function. Since <GraphPoint /> compares the previous reference to setGraphPointOn() to the newly recreated one, it will detect a change and re-render every <GraphPoint /> component.


Task 4

To solve this issue, let’s use the useCallback() hook to only recreate setGraphPointOn() when needed. Import useCallback() from 'react', then apply it to setGraphPointOn(). This function only needs to be created once with no dependencies.

Hint

Applying useCallback() to a function has the following syntax. Note the empty dependency array:

import { useCallback } from 'react'; function MyComponent(props) { const exampleFunction = useCallback(() => myFunction(), []); }

If you’re stuck, you can find the solution code in ./src/pages/Exercise4/solution/index.js.


Task 5

Reload the page with the React profiler open and click the “Show Explainers” button on and off, and notice that each <GraphPoint /> no longer is highlighted, which signifies that they are no longer re-rendered when showing the explanation dialog.

Sign up to start coding

Mini Info Outline Icon
By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.

Or sign up using:

Already have an account?