16

In this GitHub issue I essentially proposed changing:

x = useCallback( ... , []);

To:

x = useRef( ... ).current;

The two are the same but with useRef React doesn't compare the dependencies.

For which a reply came with a question:

Is there ever a situation where a dependency-less useMemo or useCallback would be a better choice than useRef?

I can't think of one, but I may have overlooked some use-cases.

So can anyone think of such situation?

Izhaki
  • 23,372
  • 9
  • 69
  • 107

3 Answers3

8

Per React Hooks API documentation:

Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render ... Using a callback ref ensures that even if a child component displays the measured node later (e.g. in response to a click), we still get notified about it in the parent component and can update the measurements.

You can read more about it here and here.

Rasuna Khatami
  • 1,021
  • 6
  • 4
  • I guess this answers the question, but I suspect this is incorrect. In the sandbox React example, changing `useCallback(x,[])` to `useRef(x)` works the same. – Izhaki Nov 15 '19 at 10:23
  • `useRef(x).current` that is. – Izhaki Nov 15 '19 at 12:35
  • I hope I'm wrong, but I've made a case for why the docs are wrong: https://github.com/reactjs/reactjs.org/issues/2570 – Izhaki Nov 15 '19 at 14:07
  • I am not entirely sure regarding `useCallback(cb, [])` vs `useRef(cb).current` myself. Although, `useMemo(cb, [])` is different to `useRef(cb).current` in a sense that `useMemo`, "will only recompute the memoized value when one of the dependencies has changed." Versus `useRef` which always recompute the value no matter what. – Rasuna Khatami Nov 15 '19 at 20:51
  • 2
    `useRef` never recomputes - it always returns the initial value. – Izhaki Nov 16 '19 at 20:33
1

While you can use useRef to emulate useCallback or with an empty dependency, You cannot use it for all possible scenarios of useCallback which is to rememoize when any of the dependency changes.

Also It won't make much of a performance difference if you use useCallback with empty dependency or useRef since it doesn't have to perform any heavy comparison.

Also if you change the function implementation a bit so that you have to recreate it on a particular param change, you can simply update the implementation with useCallback and add in the extra param as dependency. However if you implement it with useRef, you have to revert back to useCallback

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 1
    Thanks. As the title suggests, this is a strictly empty dependencies case. – Izhaki Nov 14 '19 at 13:23
  • 2
    @Izhaki I understand you question is strictly empty dependencies and that is why I mentioned that there isn't any difference in case of empty dependency. But its when you try to add in more changes, it you may need quite a bit of refactor – Shubham Khatri Nov 15 '19 at 05:47
0

Because the output of the useRef(() => {...}).current is mutable.

Which can cause weird side Effects in your code. I can change the value of current at any time. https://codesandbox.io/s/confident-monad-vjeuw

That would be the usecase for not wanting to use useRef

Daniel Duong
  • 1,084
  • 4
  • 11
  • 2
    But `x = useRef(value).current` never returns a mutable instances - `ref` is never returned; `current` is. That's the same as with the `useCallback` version. – Izhaki Nov 18 '19 at 14:05