React Memo | useMemo | useCallback - Optimize Performance of your React Applications

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Well done video overall, but there's an important bit of information that would lead to premature optimization.

Take a look at the Virtual Dom, basically even though the Child component is "re-rendering", it's only re-renders internally in react-fiber, no DOM update is actually done.

You can see this in practice by enabling Paint Flashing in chrome dev tools. Even though "Child is Rerendering" will show in the console, that div doesn't get repainted.

If you were to pass the counter as a prop and used in the child component it does repaint with the updated value!

That's the point of the React Fiber magic.

👍︎︎ 2 👤︎︎ u/uwnav 📅︎︎ Feb 09 2020 🗫︎ replies
Captions
hey guys welcome to my channel so this video will be about performance optimizations in react so if you are new and just starting out on react and I suggest you hold off on this video for now learn the fundamentals first but if you've been practicing with react for a while or if you have been making pretty big projects using react and it's noticing a performance hit now that's very rare because react for the most part is very performant but if you are noticing a performance hit in any of your components then memoization the concept of memorization maybe for you by the way guys my name is Justin here I make tutorial videos like this for react for JavaScript I make game tutorials I make algorithm videos anything related to coding you'll find it here so guys if you like my content please click like and subscribe below anyways on with with memorization alright so I created a basic reactor up here very basic no styling here we have two components we have the parent component which I am calling the app which has a state held on by you state function you stay hook counter and right now that's being displayed upon this h1 tag right now it is zero currently but I could increment the counter by using this +1 here right and also this app component renders a child called child component so right now the child component is just a stateless component and all it does is when it renders it renders its box with this child and a console logs child is rendering now I'll not talk about when a component renders alright so there's more than one ways for a component to render probably the three ways that a component will render is one it's state changes then you'll rerender number two the profs that it receives changes daniel rerender and number three and this is the one that i want to focus on right now is when the parent we renders by default the child will always rerender as well let me show that to you guys right now so let me refresh the page it says here on the console of Google Chrome child is rendering of course is rendering right in a very beginning it needed to paint this by the way what does rendering mean it pretty much does all the calculation in here and puts this div element in the h1 tag that's inside here in the return function onto Dom right so that's what rendering means and of course it's got to render in the beginning because we have to paint this onto the Dom right all right but now notice this child component has nothing to do with the counter that the parent has right we could increase the counter by pressing this button that would not affect a child anyway however every single time we click this button let's see what happens in the console right here right bambam bam-bam-bam I keep we keep on seeing child is rendering even though there was nothing that he was doing that that would that nothing is changing with this component yet because the parent is rear-ending because it's state is changing the child by default also has to rerender so for the most part this will not be an issue because again react is very performant and right now you can't even tell you can't even tell that this is rear-ending right now right and most for the most part for most applications it may be like this however there may be some components whether the component is very big or you have about a state that you're managing or whatever or it's rear-ending too many times right that's where that's what you may want to use this concept of memoization so let's talk about what that is real quick all right so what is memorization memorization is not native to react it is a speed optimization technique in programming in general so not just about react but in programming as a whole and how it works is where you give in a function you return a cache version of the output if the same inputs are used or memorize function remembers the result of an output for a given set of inputs so this is what happens so you gotta have a couple criterias to memorize a function first of all the function has to be pure what I mean by that is given our input let's say X given a set of inputs it must always return the same output so that is a one criteria for a pure function another thing is it can't have side effects those are things like I don't know that console dogs is that's not the point of this right now but pretty much it has to be a pure function and so what it does is if you give it a couple inputs it remembers those inputs and also remembers the output that's associated with it so whenever you pass in a set of inputs to a memorized function it first checks in as cache in his memory whether that input has those set of inputs have already been used or not and if it has it just instead of computing everything again it gives you back the cache output version of it in react we can memorize components where the inputs are props in this case the props that component receives from its parent you could also memorize functions or you could also memorize just regular regular computed values we will visit each of these in a small details coming up and also when memorizing components it does a shallow comparison by default it also changes by the way of the props and if it sees that he has changed an evil rerender so we're gonna kind of revisit this concept later but pretty much what this means is it does a shadow comparison of the props meaning if you are passing as props let's say an object something that's not a primitive value such as an object an array or a function it passes all it does a shadow comparison of those meaning it only checks if the reference to those two those type of odd objects have changed or not so even if it's exactly the same identical object it looks exactly the same but if it's not in the same reference in memory then it will rerender because are the real component by default things that you have passed it new props so there is a way to circumvent that and I'll show you guys a couple different ways to do that but let's just go on and finally memorization is not free you're trading space for time so what this means is to speed up your program somewhat you are using more space what that means is you are storing these set of inputs and outputs in cash in memory okay so back to our app number what it did every single time we click this button it's obtaining the counter and even though the child doesn't use it every single time we press this button our child is rendering right so to prevent this we're gonna use a memo and it's a higher-order component that we import from react it's a named import so we're gonna put curly brace and import RIA a memo from react I mean excuse me and there's two ways to uses this is a higher-order component meaning it just wraps around your component so you could either wrap this big old thing here with memo like so if I could spell correctly type correctly either wrap it like so but that looks kind of crazy I don't know about you guys so what I prefer doing is just wrapping my export like so now remember what I said what how this function works is a comparative props that this component receives if the process changed then it will rerender otherwise it will not so i refresh the page initially as always we have to render at least once but when I click this now it's not rendering anymore now let's see how we can make use out of this when we're actually passing down props to our child components so let's pass down the counter number into our child so I'm gonna add a proper called counter which will receive the prop contr let's go back to our child and I'll add the structure the counter from the props so that we could just use it without referencing props so next to the child I'm just gonna show the counter variable here now i refresh the page it'll course the renders in the beginning and we see the 0 now and whenever we do +1 it does render again which is what we wanted to do right because this component here now depends on the counter prop if the counter prop is we want this to rerender we want the number here to be updated based upon the counter number that we passed up on the parrot so this is working as intended right but now what if we had another state within our parent component so I'm back on my app let's make another how about Michael let's see an input field input variable and I'm gonna make a little input textarea where I can just type inputs and it will update this variable right here oh you state initialize it with the empty string and let's see where should I put it underneath the button maybe I'm gonna put input type is text let's see value is input and I'll make this a control component and on change whenever we type something here we will set the input oops I need the e let me put some space here set input ethat target dot value that way we will update our variable every single time we type something here so let me go back to my child let's erase this member for now just to make sure we know what we're doing right okay so like before when I click plus 1re renders right but also now that we have another state variable top whenever we update this input field here it also rear Enders but now if we use the memo and remember what memo does it compares all the props I receives right now the only props I has is the counter so whenever we update the counter it does we render as you can see here but whenever we update another state from the parent such as this input it no longer rear Enders which is ideal in this case because the child has started pen upon this state variable here of this input so this is pretty much how you use memo now right now it's working like we want because we're only passing down what's called primitive values onto the child meaning we're not passing down any functions any callback functions we're not passing down any objects we're not passing down any erase anything that's an object that is not a primitive value those may give you some prong because like I said before and this is where I'm not explaining now how men would works is it does a shallow comparison of the pervy previous props and the current process receiving right now what shallow comparison means for objects for non primitive data structures like objects arrays functions and so on it does a shallow copy meaning it just checks to see if the variable a the props that you're passing down is referencing the same place in memory so what do I mean by that let's try this let's also pass down the callback function to our child that will update the counter so this one I do update counter a name that as a prop and let's just do this we'll make an inline function and we will say set counter with counter plus one so it'll update the counter by one right and let's use this let's do structure this guy within the child in the props and below the h1 tag maybe I will have a button that has an on click event or update counter and click like so now let's see what happens right i press this even when I'm typing this now which has nothing this input has nothing to do with the child is still rendering so why is it when I click plus one is rendering when I also click this it's obviously rendering you know but why is it that even if I type here which has nothing to do with this child here even though we're passing using the memo function why is it rear-ending every time so the reason why this is happening is yes our props are just eyeballing this it doesn't change right whenever we change the input here it doesn't change the counter stays the same and the function the functionality of this function so stays the same however because we are made as an inline function like so it is every single time that this parent Bree renders we are redefining this function here this is a function that calls another function called the set counter we counter +1 as a parameter right so we are redefining this function every single time so how do we change it so the first step to actually have this component memorize this properly this prop properly is how about we first try to extract this to its own method within the app component within the parent component so maybe I'm gonna call this Const update counter from child and you'll pretty much do the same thing here so I'm gonna bring this over just make sure I get the correct ones and that it'll just be a method that does that same thing right let's see if that helps at all so instead of making an inline function I'm gonna call the update counter from child without the parentheses because we're just passing a reference to the function now let's see if it works I'm gonna type something here it's still be rendering meaning every single time that this function re-renders whenever we type to Siri renders it's creating this method again so this is not a way to use memo with callback function so how you want to pass down your callback functions properly so that your memo this memo works properly is this you want to use this thing called use callback and it's a hook that we account with and pretty much what this does is it will memorize your function so you see this method here we want to memorize this function you remember I said in the beginning that the concept memorization is not just for components while we call so memorize functions and that's what we're gonna do here so the way that you use this let me just put space here for now use callback and inside you pass in a function and what we want to do is we just want to set count the right so let's just bring this guy over actually instead of typing this in so the first parameter is the callback function that you want to memorize and the second parameter is a session array kind of like use of fact if you have used that before and this is the list of dependencies that is function depends upon so it won't recalculate this function unless one other the tendencies that you write here changes in our case it will depend upon the counter okay now let me refresh the page let's see what happens now when I type and notice it is no longer rendering so our news car back is working as intended so what happened just now this function update comma from child is always the same reference because we are using this callback function and you will only change you will only redefine this function when our counter variable changes so as long as our counter doesn't change like cleaning this input right here our function our callback function does not change the reference - it does not change and therefore because our child is memorized it is no longer we rendering upon a non related state change okay so let's revisit why we had to write counter here let's try this first of all remember we're passing a click event handler to the child and that work correctly update our counter like so but now let's say we were just starting out trying to use this used car back hook and we forgot this counter dependency and we left it like that okay so we are stalling it oh it has no dependencies don't ever remake this function let's see what happens now I click this plus I'm getting an error but just ignore that I click this plus it updated it at once but no matter how many times I click now it doesn't update so why is this happening so remember what I said about how use callback works it defines this function once and as long as your array of dependencies don't change it will not redefine you'll get so the moment we have defined it in at the very beginning he made a function where it uses this counter variable but at the time when this function was defined the counter was at zero right so the only he will not know the updated value of the counter because we are explicitly telling it not to update the function so it's counter is remains as 0 and all it does is does that counter 0 plus 1 and if I click again it are said counter 0 plus 1 the counter he does not know that the counter has been updated so that's why we to put the counter variable here is a list of dependencies and therefore he will give us the output properly okay I wanna shift focus for just a tiny bit let's review about what we learned so far we learned about how to memorize our entire component using this memo higher-order component we learned how to memorize function or callback function by using this use callback hook and I want to talk about how to memorize a computed value and we're gonna do that up in the child component we're gonna use this hook another hook call to use memo and what a completed value is just think of a computed value are just some calculation that may take a long time right and those are the things that has potential to become memorized by this use memo so let's pretend we have some crazy computed stuff going on right here okay so I'm just gonna just bake it let's just do this we're gonna have let number child number that's terrible naming sorry and we're just gonna increment this by doing a very big for loop so let's do 4 let is 0 is less than how many times should we do this loop I just want to make this a very heavily intensive completed value so we're just gonna loop maybe 500 million times how about that and then I plus plus and every single time I'm just gonna increment a child number by one okay so after that let's do this hmm down here I am gonna for whatever reason multiply my let's do this actually I'm gonna have my child number and display them like so for some reason now let's see what happens yeah so now we had this 500 right did you see this child is rendering I click this takes a little bit now it says child is rendering click it and waits a little bit and child is running the reason why there's a delay like that it's because it's computing it's going through this 500 million loop every single time so this is a compare very kind of maybe might be a stupid example but it's an example of a computer Valley or a valley that takes a little bit of time or computational time to compute and maybe it's not always smart to compute this every single time right so this is where use memo comes to play we could memorize this valley so what we can do is this let me comment this out use memo it's kind of is almost is very similar to use call back as a matter of fact so this is what we're gonna do Const child number is going to echo we're gonna use the use of memo hook it guessing or a function as a first parameter and just like they use call back and use effect I'll array up dependencies for the second one this one will not depend on anything right now and we will do this let's see let child let I'll put out this function is gonna be starting at 0 we're gonna do this for loop and instead of incremented child number we're going to increment the output and once we have calculated the output let's just return the output so this will give you the memorized value of the child mammal now so child number now I mean so when i refresh is take some time now it says child is rendering right but when I click this now the child is rendering comes immediately meaning it's not computing this every single time because it doesn't need to so again a use memo if it depends on anything like a state or a proper something then you will always write it in this array of dependencies here but because our child number here doesn't depend on anything we don't need to write anything in the array of dependencies so before we end this video I wanna go back to the higher-order component out of react memo which we were using the child right here and remember I said in the beginning that by default it only does a shadow comparison but you could change that behavior so let our nav visitor right now I'm on the official react website here and I just googled react up memo optionally notice right now we're just passing in the component as a first parameter to this higher-order component function we could also optionally pass in a second function which has this shape right here I don't know if you guys can see that it's it kind of looks like component should update and all that stuff it gets the previous props and next props and you go compare this however you like in this function well you just gotta be make sure that you write this correctly because if you don't do the proper comparisons all right I kind of cut my video right there real quick sorry about that but someone knocked on my door and my dogs were going crazy so I didn't want you guys to hear that but anyways you gotta make sure you write this carefully because if you don't compare them properly and you say oh yeah they are equal don't be rendered then you may unintentionally not render even though you were supposed to render so just be very careful about this let's say you wanted to do a deep echo so not a shallow compare but a deep echo compare right where you check every single element of an array for example and so on you can either write your own custom one or if you're lazy you could you could npm install no - i'm pretty sure most of you guys are familiar with this and i'm gonna search their documentation right now and look at this is echo one it says it performs a d-- comparison between two values to determine it they're equivalent so this supports a raise or a buffer boolean blah blah blah and all that stuff so if you're feeling lazy what you can do is make sure you have low - installed you could import let's see what is it's called is equal from low - and you could use this but before we do this let me just show you guys the difference between without using this and with using this I'm gonna have the parent component render just like a stupid array every single time so I'm just cuz i const r is equal to 1 2 3 and we will pass this array to our child so let's see what happens right i don't even need to destructuring from the child because it's still receiving as a problem even though our child is memorized if i write something here no not in my console right here our child rear Enders why because every single time the parent rear Enders he is redefining the parent is really fine disarray even though it's the same so let's say we didn't we wanted the child to do a tipico comparison for the property receives so what we can do is as a second parameter just pass this is equal function that lodash comes with and now check this out I write something it doesn't rerender so if you're feeling lazy you could use this as equal from low - or maybe you want to make it more optimal because this might not be the most optimal way to do things because it might do a little bit more comparison than is needed then you could write your own custom one let's say like right here Const are equal and using this structure right here you could try to come up with your own function that does this anyways guys I think this videos been going a lot longer than I initially intended but that's fine hopefully you guys learned something from this and make sure that you guys only use I would recommend that you guys only use these memorization techniques when you are noticing or performance hit because many times I feel like many people don't use them correctly and for the most part we act is very performant like I said again so you usually don't need it anyways guys if you guys like my content please click like and subscribe below I release these type of coding videos on almost every single day basis so guys stay tuned and I will see you guys next time
Info
Channel: Justin Kim
Views: 17,609
Rating: 4.9754348 out of 5
Keywords: Javascript, React, Programming, ES6, ECMAScript, Coding, Tutorial, Code Alongs, 2020, Hooks, useState, memo, memoization, render, Lifecycle Methods, React.memo, state, props, useCallback, useMemo
Id: 3cYtqrNUiVw
Channel Id: undefined
Length: 25min 53sec (1553 seconds)
Published: Sun Feb 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.