reactjs / reactjs/react.dev

useCallback vs useRef misguidance (confounding useRef with object ref)

未關閉
#2,570 1 則留言 18 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

主要語言
JavaScript
星號
11.8k
分支
7.9k
平均合併
1 天 11 小時
30 天內合併 PR
11

描述

The Proposal

As part of a deductive exercise, in this issue I essentially proposed changing:

x = useCallback(cb , []);

To:

x = useRef(cb).current;

With useRef:

  • No deps comparison (Object.is).
  • No reallocation of empty array on each render.

These optimisations are terribly minute, but understanding React is what at stake here.

The Question

Then the reply came:

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

The Docs

I couldn't think of one, so posted an SO question, for which a reply came with reference to these docs:

We didn't choose useRef in this example because an object ref doesn't notify us about changes to the current ref value. 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.

In the codesandbox example provided, we see useCallback with empty dependencies:

  const measureRef = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }, []);

Yet changing the useCallback above to useRef(cb).current works all the same:

  const measureRef = useRef(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }).current;

Misguidance?

Now I understand the docs focus on a callback ref, so using useCallback makes sense.

But this statement is misleading:

We didn't choose useRef in this example because an object ref...

First, it promotes the (in my view somewhat popular) misconception that useRef is solely there to refer to DOM elements (filled via object ref).

Further, this statement confounds useRef with object ref:

  • object ref vs callback ref is one thing
  • useRef is another.

What useRef is Really for

Far from this, useRef raison d'être is the ability to create stable values; callbacks are no exception:

const stableCallback = useRef(()=> { ... }).current;

Storing DOM elements is a popular, yet a specific use case for refs.

Another Example

From the docs:

Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.

I argue that this statement distorts people's understanding of core React concept. It builds a mental model where there is such 'cosmic' mapping:

  • useRef → object ref
  • useCallback → callback ref

This is incorrect.

(Nitpickers, like me, will point out at this point that both "object ref" and "callback ref" have "ref" in them!)

What needs changing?

First, useRef should not be part of this sentence:

We didn't choose useRef in this example because an object ref...

Instead:

We didn't use an object ref as it doesn't notify...

Also this:

Keep in mind that useRef doesn’t notify you when its content changes...

To this:

Keep in mind that object refs don't notify you when its content changes...

Then, if useRef(cb).current is identical to (and slightly more efficient than) useCallback(cb, []), perhaps this is something worth mentioning?

More generally, if correct, I would expect to see this somewhere in the docs:

useMemo(x, []) and useCallback(cb, []) are the identical to useRef(x).current and useRef(cb).current respectively.

Learning this is conceptually important, thus so is teaching.

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

從所引用的 hooks-faq.md 和 hooks-reference.md 部分開始,並結合 issue 提議的措辭檢查 callback-ref 範例。在決定應更改哪些術語或說明之前,先驗證關於物件 ref、useRef、useMemo 和 useCallback 的說法是否準確;完成的標準是文件在技術上準確,且區別清楚。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
javascript, react
領域
documentation
Issue 類型
文件
難度
4/5
預估耗時
3-5 天
活躍度
停滯
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。