I completely understand why you would want to memoize values and reasons to use useMemo. But I don't really understand why you would want to memoize a function to avoid it being re-generated. I guess maybe it saves a tiny performance hit, but does useCallback result in significant performance improvements?
If you're passing the callback as a prop to a child component, then it will cause that component to be re-rendered every time the parent component renders unless you memoize the callback. This happens because React checks referential identity when determining whether props have changed. The performance hit of unnecessary re-renders can be fairly significant in large React apps.
React will rerender the child component anyway in this case even with useCallback. Of course you can prevent this by using React.Memo on the child component, and in this case using useCallback makes it possible to optimize rerendering by providing stable values for functions you pass to that component.
Adding useCallback for functions only does something useful if you also React.Memo those children. So while this is a very important optimization, it's not one you need to apply to everything.
Memoizing the callback prop only matters if you wrap the child component in "React.memo".
If you don't wrap the child component with "React.memo", every time the parent renders the child will render regardless of prop equality, even with memoized props/callbacks.
It actually doesn't directly help performance at all, because you're still creating a new function each time; they just get thrown away after the first time (until dependencies update)
It only exists/is done to give you a stable reference so you can avoid triggering downstream dependencies (hook arrays and React.memo'd components)
Yes, it gets allocated in memory (assuming there isn't some kind of crazy runtime optimization that can figure out it won't be called and skip doing that)
One reason useCallback exists is because useMemo, too, allocates a function on every render- even if it doesn't recompute the underlying value by actually calling the function. So if you're going to be allocating a function anyway, there's no point (performance-wise) to allocating a function that creates a function. You can just cut out the middle-man
The virtual DOM is a tree, and if roughly balanced, the path that needs to be updated is of size log(N) compared to the full tree of size N that will be updated by default.
In practice, it's the difference between a stuttering app that lags at every keypress in an input field, and something usable.