But the effect is identical if you use useEffect and then set this result to something like a filteredItems state variable. By definition, neither useMemo or useEffect will fire unless items changes (as long as the dependency array remains as just [items]. Granted, going the useEffect way of doing it would introduce a new state variable. But probably for something like this you would want a state variable for it anyway.
The issue is when you call useEffect for this, this will not happen during initial render phase.
State set -> react realizes it needs to fire an effect -> usEffect runs -> state set again (filteredItems) -> re render
So you see this is not very performant.
While if you use useMemo (or just simply calculate result without memo), react can calculate result during render which is more desirable
What useMemo spits out is a state variable. If you change state in useEffect, you trigger another render cycle with new state. useMemo does not do this, it calculates the derived state in the current render cycle (during render), only if its dependencies have changed. useEffect is for side effects only.
Well, I made an example to finally prove what I mean. You can clearly see by both methods (either useEffect or useMemo) that the component is render twice. So its two ways of doing the exact same thing, exact same 'efficiency', the benefit with useEffect is that you get your statevariable you can use later:
Yea... Because you put the console.log inside the useEffect hook for your useEffect example :B I updated your code example for you, so it's a fair comparison: codesandbox.io/s/distracted-goldst...
In the image you can clearly see React 18 mounting the components and doing everything twice and then you can see the 2nd render caused by the useEffect hook updating state.
Really... this rule is not a joke: useEffect is only for side effects and should not be used for derived state, thats what useMemo is for, they didnt add this hook because they were bored. If you refuse to use the useMemo hook, you should STILL not use the useEffect hook for derived state. Just use a plain old javascript variable, it has better performance than triggering a 2nd rerender.
Ok, I admit that example was stupid since I would anyway probably do that as you mentioned just with JavaScript. Therefore, I still can't see a case you would want to do useMemo anywhere. See the newest example: the "JavaScript" only, as you said, is the most efficient, better than using either useMemo or useEffect:
I think the problem is from the beginning that the original useMemo example presented would probably only make sense if the 'derived state' of question actually has dependencies on other state variables, then maybeuseMemo affords you some advantage, but the way I see it, when each dependency required for this derived state changes you're going to get a rerender, regardless of if you use useMemo or useEffect. This is why stupid arguments like this are such a waste of time and composition is one of the most important skills of writing good React components.
No... there's a real functional difference. Updating state in a useEffect hook triggers another rerender on top of the rerender you were already getting from the state update that caused the dependencies of your useEffect hook to change. It's very important to understand this if you're going to be using React hooks, because otherwise you will run into performance issues and unexpected app behavior down the line. useMemo does not trigger a rerender, regardless of how many dependencies you pass into it.
You can opt for putting the logic to calculate your derived state directly into the render function of your component, however, that too can become a problem, for example if you try to render a lot of components at the same time and all of them have a bunch of junk happening inside their render functions, your app will become slow, to a point where it becomes unusable.
It's not an argument, it's a fact that useMemo works this way. It memoizes expensive calculations, so they dont have to happen on each render if the dependencies did not change.
For derived state, its highly recommended to use the
useMemo
hook.That way you avoid doing expensive array manipulation during each render cycle, even if the items did not change.
But the effect is identical if you use
useEffect
and then set this result to something like afilteredItems
state variable. By definition, neitheruseMemo
oruseEffect
will fire unlessitems
changes (as long as the dependency array remains as just[items]
. Granted, going theuseEffect
way of doing it would introduce a new state variable. But probably for something like this you would want a state variable for it anyway.The issue is when you call
useEffect
for this, this will not happen during initial render phase.State set -> react realizes it needs to fire an effect -> usEffect runs -> state set again (
filteredItems
) -> re renderSo you see this is not very performant.
While if you use
useMemo
(or just simply calculate result without memo), react can calculate result during render which is more desirableWhat
useMemo
spits out is a state variable. If you change state inuseEffect
, you trigger another render cycle with new state.useMemo
does not do this, it calculates the derived state in the current render cycle (during render), only if its dependencies have changed.useEffect
is for side effects only.Well, I made an example to finally prove what I mean. You can clearly see by both methods (either useEffect or useMemo) that the component is render twice. So its two ways of doing the exact same thing, exact same 'efficiency', the benefit with useEffect is that you get your statevariable you can use later:
codesandbox.io/s/dreamy-wood-nrvfz...
Yea... Because you put the
console.log
inside theuseEffect
hook for youruseEffect
example :B I updated your code example for you, so it's a fair comparison:codesandbox.io/s/distracted-goldst...
In the image you can clearly see React 18 mounting the components and doing everything twice and then you can see the 2nd render caused by the useEffect hook updating state.
Really... this rule is not a joke:
useEffect
is only for side effects and should not be used for derived state, thats whatuseMemo
is for, they didnt add this hook because they were bored. If you refuse to use theuseMemo
hook, you should STILL not use theuseEffect
hook for derived state. Just use a plain old javascript variable, it has better performance than triggering a 2nd rerender.Ok, I admit that example was stupid since I would anyway probably do that as you mentioned just with JavaScript. Therefore, I still can't see a case you would want to do
useMemo
anywhere. See the newest example: the "JavaScript" only, as you said, is the most efficient, better than using eitheruseMemo
oruseEffect
:codesandbox.io/s/festive-chatelet-...
I think the problem is from the beginning that the original
useMemo
example presented would probably only make sense if the 'derived state' of question actually has dependencies on other state variables, then maybeuseMemo
affords you some advantage, but the way I see it, when each dependency required for this derived state changes you're going to get a rerender, regardless of if you useuseMemo
oruseEffect
. This is why stupid arguments like this are such a waste of time and composition is one of the most important skills of writing good React components.No... there's a real functional difference. Updating state in a
useEffect
hook triggers another rerender on top of the rerender you were already getting from the state update that caused the dependencies of youruseEffect
hook to change. It's very important to understand this if you're going to be using React hooks, because otherwise you will run into performance issues and unexpected app behavior down the line.useMemo
does not trigger a rerender, regardless of how many dependencies you pass into it.You can opt for putting the logic to calculate your derived state directly into the render function of your component, however, that too can become a problem, for example if you try to render a lot of components at the same time and all of them have a bunch of junk happening inside their render functions, your app will become slow, to a point where it becomes unusable.
It's not an argument, it's a fact that
useMemo
works this way. It memoizes expensive calculations, so they dont have to happen on each render if the dependencies did not change.Yeah, exactly. Although
filteredItems
above is technically not a state variable, but a derived value.