Gist
Acoording to React 18 Changelog:
In the future, React will provide a feature that lets components preserve state between unmounts...
For further actions, you may consider blocking this person and/or reporting abuse
For derived state, its highly recommended to use the
useMemohook.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
useEffectand then set this result to something like afilteredItemsstate variable. By definition, neitheruseMemooruseEffectwill fire unlessitemschanges (as long as the dependency array remains as just[items]. Granted, going theuseEffectway of doing it would introduce a new state variable. But probably for something like this you would want a state variable for it anyway.What
useMemospits out is a state variable. If you change state inuseEffect, you trigger another render cycle with new state.useMemodoes not do this, it calculates the derived state in the current render cycle (during render), only if its dependencies have changed.useEffectis 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.loginside theuseEffecthook for youruseEffectexample :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:
useEffectis only for side effects and should not be used for derived state, thats whatuseMemois for, they didnt add this hook because they were bored. If you refuse to use theuseMemohook, you should STILL not use theuseEffecthook 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
useMemoanywhere. See the newest example: the "JavaScript" only, as you said, is the most efficient, better than using eitheruseMemooruseEffect:codesandbox.io/s/festive-chatelet-...
I think the problem is from the beginning that the original
useMemoexample presented would probably only make sense if the 'derived state' of question actually has dependencies on other state variables, then maybeuseMemoaffords 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 useuseMemooruseEffect. 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.You say "don't use useEfffect for event handlers" and you are totally right, but unless you are using a primitive html element, the best solution for callbacks and event handlers is not in-lining it, rather than you should use useCallback in that case
useCallbackdoes make sense; but only when the function creation is expensive. If you are wrapping a simple function (as in example); it is actually slower that withoutuseCallback. A new hookuseEventis coming into React soon that would solve this problem (no need to pass dependencies): github.com/reactjs/rfcs/blob/useev...Until then, we should sure not to pre-maturely opt for "optimizations" if you will.
Kent C Dodds has written a great article on this: kentcdodds.com/blog/usememo-and-us...
Hi,
I have read that article, and is really really cool.
However, I think that
useCallbackshould be used not only when the function creation is expensive: the main purpose ofuseCallbackis to memorize the function, hence it's reference, in order to be able to pass it as a prop to a component without causing it (and all of its childs) to rerender because of a function prop change.Now, if the callback is used to be passed as a prop to a "native" component (like html button for example), it does not have any child and so it shouldn't cause so much troubles. But, for example, if the callback is to be passed to a component's props, and that component then will pass it to a button component, that function reference change will cause the component that renders the button to re-render all its childs as well