Performance Improvement by useCallback, useMemo and React.memo
samundrak
JavaScript DevReact is fast on its own, It does a lot of work to make our web app more fast and smooth and on top of that today's browser engine is doing a perfect job to optimize the code we throw to them. v8 has TurboFan which does some next level of optimization. These are the things that are done for us by someone else but there is still a lot of things that we can do to improve our application. I will not write about web application performance and optimization process here because this note was specially written for optimizing React apps which uses hooks and I mentioned other things because sometimes we do overengineer in the name of performance, which I think I do sometimes (Premature Optimization).
I use React hooks a lot and many times I get stuck thinking about how I can make it work faster, which hook can be useful here to store data, memoize data, etc.
React.useCallback
When we have to pass a callback to some component then we can use useCallback
hook. React will store function and will always return the same referenced function. If we pass dependency then React will update the function.
Callback without dependency
Sending empty array as the second argument means that it doesn't have any dependency and there is no need to create a new reference of function on every render. React will just store it and on every render if asked it will provide previously created function instead of creating new on every render.
Callback with dependency
When we provide dependency to useCallback
React will notice it and whenever there will be changes in dependency then React will create a new function and return it and will cache it again. Passing a variable in dependency array doesn't mean you will get that as an argument in the callback, It just hints React to remove old function which referenced to old dependency and create new function declaration.
useCallback
caches function and not return value of the function. It is memoization to React but not for us.
React.useMemo
useMemo
can be confused with React.memo
because of both having memo in common but they have their own feature and properties. Normally in the class-based component, we create many methods and those methods are invoked only when they are called
but if we use functional components and create a function inside it then they are created on every render which can cause performance issues. Most of the time React handles issues if remounting and rerendering but it still had to do invoke methods or
any calculation that are done inside a function like finding value in the array, calculating or aggregating data from an array.
We can avoid those calculations to be done again and again by using useMemo
hook. This hook takes a function as the first parameter and dependency as the second parameter and whenever the value of dependency is changed then useMemo
will recalculate or invoke its first parameter and return it. For string, number, and other primitive data it will be a value check but for the object it will be a reference check. If the object passed as a dependency has the same body schema but is from some other reference than passed before then useMemo
will think that the value has been changed and will recalculate or reinvoke memoized stuff.
In the example given above, useMemo will invoke its first parameter only when referring to data is changed.
React.Memo
React.memo
is a helper function that React provides to the memoize component. Normally when we create a class-based component
we see React.PureComponent
used in many places. What React.PureComponent
does is, it just does a shallow comparison.
This means if props have a prop whose value is an object then PureComponent
will not compare it and will do just reference check. If props are the same as props passed before then React will avoid doing rerendering. This is a class-based component and to achieve the same thing in the functional component we can use React.memo
.