← React Course

REACT ADVANCED · 141

Refs:當你需要記住東西,但不想觸發 Render

State 會驅動 UI;ref 則適合保存不需要 render 的 mutable value,或取得 DOM node 做 imperative interaction。把兩者混用會讓 UI 和資料不同步。

Learning outcomes

1. DOM ref

const inputRef =
  useRef(null);

function focusSearch() {
  inputRef.current?.focus();
}

return (
  <input
    ref={inputRef}
  />
);

這是合理的 imperative escape hatch:focus 是 Browser DOM behavior。

2. Ref mutation 不會觸發 re-render

const countRef =
  useRef(0);

countRef.current++;

畫面不會因這行自動更新。如果 UI 應顯示這個值,就應該是 state。

3. 保存 request/timer handle

const controllerRef =
  useRef(null);

function cancelCurrent() {
  controllerRef.current
    ?.abort();
}

4. Previous value / instance-like mutable container

ref 可以跨 render 保存 mutable data,而不重新 render;但應用場景要明確,避免把它變成逃避 state model 的暗門。

4.5 Ref 的讀寫時機也要有紀律

Render 應主要依 props/state 計算 UI;不要在 render 過程把 ref 當一般 mutable global 到處讀寫。DOM ref 通常在 commit 後才對應到實際 node,imperative 操作應放在 event/effect 等適當時機。

function handleOpen() {
  dialogRef.current
    ?.showModal();
}

這讓 imperative action 有明確觸發點,而不是在每次 render 都偷偷操作 DOM。

Project checkpoint:Search focus + cancellation

const inputRef =
  useRef(null);

const controllerRef =
  useRef(null);

function startSearch(query) {
  controllerRef.current
    ?.abort();

  controllerRef.current =
    new AbortController();

  // fetch with signal
}

Debug evidence:UI 顯示舊值

如果你把應該驅動畫面的資料放 ref,ref.current 雖然已變,但沒有 state update 觸發 render。先確認「這個 value 是否應該影響 UI」。

Knowledge check

  1. state 與 ref 的最大語意差別?
  2. 為什麼 focus() 適合 ref?
  3. 為什麼 score 顯示不應只放 ref?
  4. 用 ref 保存 AbortController,設計取消上一個搜尋 request。