This course has been updated! We now recommend you take the Intermediate React, v5 course.
Transcript from the "useCallback" Lesson
[00:00:00]
>> So we're gonna go move on and talk about useCallback. This is gonna look really familiar to you because it's relatively the same thing. And actually useCallback is implemented by using useMemo internally. So they actually have the same sort of mechanism. So, same sort of thing here, notice we have used callback here, and we have a timer that's counting up here.
[00:00:32] But notice this last rerender here is 11:36, so it's different from what's down here. But as soon as I click this current count, it does rerender down here, right? So it's only re-rendering every time that I increment this. Let's talk about why that is. So I have this expensive computation component, which is doing the same thing, it's using Fibonacci again, right?
[00:00:57] Compute, where's my compute function here? It's coming from that, okay? And then here I have my Fibonacci again. But just you can replace this in your brain as a really expensive thing to compute, right? So here the callback component, the parent component, I have the time, the set time, right, and that's counting up here.
[00:01:20] And then I have the count and set count, so that's what this is. It's just counting up. And then I have an effect here in the parent component that's counting up, right, or rather it's updating with the time. Okay, I have my Fibonacci here. And then down here, What I'm doing is I'm passing into the expensive computation component down here, useCallback with Fibonacci, and then I'm just telling it to not re-render, unless it changes, right?
[00:02:00] So why do we do that? Cuz Fibonacci is actually being calculated down here in the expensive computation component. And the reason why that's bad, if I just pass in Fibonacci directly here, Notice this is now re-rendering every single time, why? Well, Fibonacci here which exists inside of callback component gets recreated every single time that we re-render the component.
[00:02:34] So every time, this is actually going to be a different function that does the same thing, right? But to react down here in expensive computation component, it says, hey, compute is changing every single time. Why does it think that? And why does it matter in this particular case?
[00:02:53] Well count, if you have like x = 5, right? And then later I go back to say, hey, is x = = = 5? The answer is, yeah, right, it is. However, if I have a function here, Function y. Okay, let's do it this way. Why does it stopped doing that?
[00:03:29] Okay, I have cons y = generic function, right? This is just like the most basic function, let's even just do this. All right, it's just a generic function here. If I go back and ask later is y = = = function like that? It's not, right? They're both empty functions but they're different empty functions, okay?
[00:04:00] Why is that important? That's important because expensive computation component is judging, do I need to re-render by looking at the props and saying is count the same. Yeah, it's the same. Is compute the same? No, I got a different compute this time, right? It's the same function, but it's the same principle here of like it's different, right?
[00:04:19] It's a different instance of the same function because I'm recreating it every single time here in this render function, right? That's a problem. That's why, you don't want that anyway, we can get rid of that That's a problem here because, if this number starts getting really big, let's make this 30 again.
[00:04:49] It's re-computing this every single time because this compute thing is coming back different. So this is what useCallback does for you. If I put now useCallback And I say Fibonacci is never changing, it's always the same one. Therefore, this will not re-render cuz it's giving it back the same function, right?
[00:05:18] In the same way that useMemo is giving you back the same thing over and over again. Now, it's a very specific use case here. There's a bunch of ways that you could optimize people saying, like, why don't we just pull Fibonacci out? That's a wonderful idea and you should definitely do that, right?
[00:05:36] But there are specific use cases where useCallback here can be helpful to help your app not unnecessarily re-render. All right, let's make that so it's not doing that every single time. 30, let's put that down to 1. So again, very specific performance optimization. But I guess what the major takeaway from you here is, the way that React decides, am I gonna re-render or not, is it checks your props and it say, okay.
[00:06:05] Compute encountered the same thing not gonna re-render this, even though the parent has to re-render, it'll just give you back the same result before for the child component if the props don't change. That's again my side effects are very important that you're not causing side effects in your render functions, yeah.
[00:06:24]
>> There's a question in the chat about the memo function there on line four and I'm curious, yeah, is that part of what's necessary to have this useCallback function?
>> Yes. So, memo is a function that comes from React, that allows this kind of thing to do here, which is to say that it checks the props and only re-renders it.
[00:06:47] Otherwise, it would just do it anyway. I think if I just got rid of that. Now, notice down here, it's re-rendering every single time. So yeah, what I was just saying about it checking the props, that only applies if memo is applied. Yep, But now notice I put it back in, and it is not re-rendering.
[00:07:30] Cool, other questions? I see a lot of people that will always wrap their components in memo as well, terrible idea. Again, in general, React is very fast, and so this re-compute are very fast. And so you typically don't have to worry about these performance optimizations. Only use memo when you actually have an expensive component to render.
[00:07:55] Now, I'm showing you this with like an expensive function like Fibonacci. But imagine if you had like a spreadsheet component that had,100,000 lines in it, that's a really good thing that you might put memo on it. And you might use some of these things on it where it's really expensive to render 100,000 lines of a spreadsheet.
[00:08:16] Sometimes you might need to re-render it. You only wanna re-render when you absolutely have to. That makes sense? But honestly, you probably still wanna check the performance profile, you might still wanna re-render it, who knows? Okay, any other questions about useCallback.
>> As so we can't use useCallback without memo?
[00:08:46]
>> Probably, I'm struggling to think of when you could. Let's say that they're almost always hooked together. I'm sure someone can invent the reason why not to. But the primary reason is that you would want to cause your child's component to not re-render when you're passing it a function, which would require useCallback or would require memo.
[00:09:07] So you can use memo without useCallback, but I'm pretty sure you can't use useCallback without memo. If I'm wrong, someone correct me in the chat.
>> So to clarify, memo is checking the props to see if they changed to re-render, I thought React already did this?
>> It doesn't, no, React is just gonna re-render.
[00:09:33] Yeah, I kind of misspoke a little bit earlier on that.
>> Is what they're thinking of is probably the dependent arrays that we pass to our hooks.
>> Not sure I understood what you said.
>> I'm guessing what this user was thinking and guessing and checking the props to see if they changed through under, that sounds like the behavior about dependency arrays that we pass.
[00:09:56]
>> I think it's pretty close, yeah. I mean, the long story short is just making sure that this use or this Fibonacci that you're passing to it is the same callback everything single time. Anyway, I've never had professionals use this. We've spent a bunch of time learning about it.
[00:10:27] I've never had any professional use useCallback. So it is not the most useful. And I've actually heard someone on the React core team say that they probably should have just left it with useMemo and let users re-implement useCallback themselves. It is a fairly nice use case