I'm reading about hooks in React, and I have some trouble understanding the difference between useRef and useCallback hooks.
Specifically, I'm looking to understand how these two can be used to avoid unnecessary re-renders of child components.
Based on my understanding of this answer on stack overflow, the following function can be written as:
const Avatar = function({ history, url, fullName }) {
const onMenuItemClick = urlToNavigate => history.push(urlToNavigate),
onMenuItemClickRef = useRef(onMenuItemClick);
return (
<Menu
label={<RoundedImage src={url} alt={fullName} />}
items={[
{ label: `Logged in as: ${fullName}` },
{
label: "Liked articles",
onClick: () => onMenuItemClickRef.current("/liked-articles")
},
{
label: "Edit profile",
onClick: () => onMenuItemClickRef.current("/profile")
},
{ label: "Logout", onClick: () => console.log("Logging out") }
]}
/>
);
};
Would it also make sense to replace:
const onMenuItemClick = urlToNavigate => history.push(urlToNavigate)
with:
const onMenuItemClick = useCallBack(urlToNavigate => history.push(urlToNavigate), [urlToNavigate])
so it changes only when urlToNavigate changes?
The useCallback hook is used when you have a component in which the child is rerendering again and again without need. Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.
The useRef Hook allows you to persist values between renders. It can be used to store a mutable value that does not cause a re-render when updated. It can be used to access a DOM element directly.
useMemo is very similar to useCallback. It accepts a function and a list of dependencies, but the difference between useMemo and useCallback is that useMemo returns the memo-ized value returned by the passed function. It only recalculates the value when one of the dependencies changes.
useRef(initialValue) is a built-in React hook that accepts one argument as the initial value and returns a reference (aka ref).
In the link you reference in your question the key is that the children component (the one that receives the callback) is memoized.
In a normal Parent > Children cycle, every time a prop from Parent changes it will re-render and Children too, even if no props from Children changed.
If we want to avoid Children from rendering when non of its prop changed then we can memoize the component (React.memo). Once we do so, we might have a problem if in Parent we create a function callback on every render, because the memoized Children will interpret as a new function and thus will render again.
To avoid this we can use useCallback
in Parent, so when children receives the callback it knows if it is new and should render or not.
Using useCallback
when the children is not memoized does not help because Children will render anyway if Parent renders.
Regarding using useRef
for the function, I am not totally sure but I would say that it might be similar to using a useCallback
with an empty array as dependencies.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With