Memoize a Function with useCallback in React

Tyler Clark
InstructorTyler Clark
Share this video with your friends

Social Share Links

Send Tweet
Published 3 years ago
Updated 2 years ago

The useCallback hook returns a memoized callback. To be more specific, useCallback will return a memorized version of the callback that only changes if one of the dependencies passed in the second parameter array has changed. This is particularly useful when working with optimized components and to goal is to avoid unnecessary re-renders, due to prop changes.

Instructor: [0:01] Inside of my Products page, I have a bunch of individual products. These components that hold this information, you see here in the image, in the hovering, that lives inside of this productcard.js file.

[0:15] I want to add a Dislike and Like button, some type of incremental button that we can display on the products, that users can come in and upvote on. That's just going to be a little component here. I'm calling it Count button. It's just returning a button with an OnClick handler that's it's being passed from its parent.

[0:36] You notice that this is a memoized function, which basically means that, only rerender this component if the OnClick or Count changes. It's an optimized functional component. With that in there, we're obviously going to need to work with some kind of state. Inside of the parent of what would be the Count button child component, I'm going to add in some state.

[1:01] Two sets of useStates. One for Likes. One for Dislikes. Then some type of counting and set count for those counts. I have some static functions here that are basically setting the count by upping it by one for both of the two counts.

[1:22] Then with that state in there, let's just up here at the top, add in the Count buttons that I've created up here with our console.log. Passing in their individual count state, which initially is zero for both and then their functions Liking and Disliking.

[1:40] Again, basically these functions are just incrementing by one. There are corresponding counts. You'll notice on the initial load there are going to be 378, which is twice as many of the products as there are because there are two per product.

[1:58] As I increment each one of these, notice that it's actually rerendering both of the counter button components here. Instead of just the one that really needs to be rerendered, which is the one that I'm clicking on. It's changing by twos and you see that on each one.

[2:18] We really just want the numbered component that changes to rerender and not both of them. How do we accomplish this? Before we do that, you might be thinking, why is it doing that? Again, we're using React.memo() on this function.

[2:35] Why would it be rerendering the second Count button when only one of them is changing? Only one of the props is changing. It's due to reference reference equality.

[2:45] This function is being recreated, which is passing in a new function reference to our Count button, which then rerenders it. What we want to do is actually pass this as a useCallback hook function. We'll do React.useCallback. This is wrapping that function in the first param.

[3:08] The second is a dependency array, which I'm going to leave as empty because this function is never going to change. We'll do the same thing for the second function. React.useCallback with an empty array.

[3:27] We'll save that and check it out, but we'll come back and review this again. Notice that we get the initial two per product card rendering here, but as we update the components, it's only rerendering one at a time.

[3:43] To recap again, this useCallback hook is going to return a memoized version of this function that will only change if one of the dependencies passed here changes. With an empty array, it's never going to be recreated. It's going to memoize it as is.

[4:02] Though, if you add in any dependencies and those change, you'll get a new function here. This is taking our memoized component here to the next level and making sure that this doesn't rerender unnecessarily.

egghead
egghead
~ just now

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today