SKILL.md
唯讀
名稱
react-best-practices
描述
在讀取或撰寫 React 元件(.tsx、.jsx 檔案,有 React 匯入)時使用。
React 最佳實務
搭配 TypeScript
使用 React 時,請同時載入此技能與 typescript-best-practices。TypeScript 模式(型別優先開發、差別聯集、Zod 驗證)同樣適用於 React 程式碼。
核心原則:Effect 是逃生門
Effect 讓你「跳出」React 以同步外部系統。大多數元件邏輯不該使用 Effect。 在撰寫 Effect 前,先問:「有沒有不用 Effect 的方法?」
決策樹
- 需要回應使用者互動? 使用事件處理器
- 需要從 props/state 計算值? 在渲染時計算
- 需要快取昂貴的計算? 使用
useMemo - 需要在 prop 變更時重置 state? 使用
keyprop - 需要與外部系統同步? 使用 Effect 並清理
- 需要在 Effect 中使用非反應式程式碼? 使用
useEffectEvent - 需要不會觸發渲染的可變值? 使用 ref
何時使用 Effect
與外部系統同步:瀏覽器 API(WebSocket、IntersectionObserver)、第三方非 React 函式庫、window/document 事件監聽器、非 React DOM 元素(影片、地圖)。
何時不使用 Effect
- 衍生 state — 在渲染時計算
- 昂貴的計算 — 使用
useMemo - 在 prop 變更時重置 state — 使用
keyprop - 回應使用者事件 — 使用事件處理器
- 通知父層 state 變更 — 在同一個事件處理器中更新兩者
- Effect 鏈 — 在一個事件處理器中計算衍生 state 並更新
Refs
- 用於不影響渲染的值(計時器 ID、DOM 節點參考)
- 渲染期間絕不讀取或寫入
ref.current;僅在事件處理器和 Effect 中操作 - 對於動態列表,使用 ref 回呼(而非在迴圈中使用
useRef) - 使用
useImperativeHandle限制父層可存取的內容
自訂 Hook
- 共享邏輯,而非 state — 每次呼叫都會取得獨立的 state 實例
- 僅在實際呼叫其他 hook 時才命名為
useXxx;否則使用一般函式 - 避免生命週期 hook(
useMount、useEffectOnce)— 直接使用useEffect,讓 linter 能捕捉遺漏的相依性 - 專注於單一具體的使用案例
元件模式
- 受控:父層擁有 state;非受控:元件擁有 state
- 偏好使用
children組合而非 prop 鑽遞 - 將切換大型元件樹的布林 prop(
isEditing、isThread、hideAttachments)視為組合的壞味道;針對不同使用案例,偏好使用獨立的組合元件 - 對於複雜的可重複使用 UI,偏好使用複合元件搭配 provider 範圍的 state/actions,而非帶有許多選擇性 prop 的單一元件
- 對於範圍內的元件家族以及真正的全域 state,使用 Context,只要它定義了由後代消費的區域介面
- 直接渲染 JSX 以實現 UI 變化;避免使用設定陣列的迷你框架,除非設定是真正的領域資料
- 當兄弟或外部控制項需要存取相同的 state/actions 時,提升 provider 邊界
- 當需要在 state 更新後同步讀取 DOM 時,使用
flushSync
請參閱 react-patterns.md 以取得程式碼範例和詳細模式。






