REACT ADVANCED · 141
Refs:當你需要記住東西,但不想觸發 Render
State 會驅動 UI;ref 則適合保存不需要 render 的 mutable value,或取得 DOM node 做 imperative interaction。把兩者混用會讓 UI 和資料不同步。
Learning outcomes
- 能區分 state 與 ref。
- 能用 ref 取得 DOM node。
- 能保存 timer/request handle。
- 能辨識「把 UI data 偷塞 ref」的錯誤。
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
- state 與 ref 的最大語意差別?
- 為什麼 focus() 適合 ref?
- 為什麼 score 顯示不應只放 ref?
- 用 ref 保存 AbortController,設計取消上一個搜尋 request。