Vue 3 Composable 完全指南:如何開發可重複使用的邏輯函數?
在開發 Vue 應用程式時,是否常遇到邏輯重複、元件過於肥大的問題? Composable (組合式函數) 正是為了解決這些痛點而生。簡單來說,Composable 是將可重複使用的 狀態與行為 封裝成獨立的 function,讓程式碼更簡潔、更好維護。
什麼是 Composable?
Composable 是 Vue 3 Composition API 的核心應用。它利用 Vue 的響應式系統,例如:ref(), reactive(),將特定的功能邏輯抽離出元件。這不僅提高了程式碼的複用性,也讓單元測試變得更加容易。
它與一般工具函式的差別,在於 它會用到 Vue 的能力:
| 類型 | 會用到響應式與生命週期嗎 | 放在哪裡 |
|---|---|---|
| Composable | 會,例如:ref、computed、onMounted | src/composables/ |
| 工具函式 | 不會,純輸入輸出,例如:日期格式化 | src/utils/ |
常見的 Composable 使用情境
以下是開發中最常被封裝成 Composable 的功能模組:
| Composable 名稱 | 功能用途說明 |
|---|---|
| useFetch | 封裝 API 請求邏輯、處理 Loading 與 Error 狀態 |
| useAuth | 管理使用者登入狀態、權限檢驗與 Token 存取 |
| useMouse | 追蹤滑鼠座標位置 |
| useLocalStorage | 簡化與瀏覽器 localStorage 的同步操作 |
本系列會實作其中三個:計數器 useCounter、滑鼠座標 useMouse、非同步請求 useFetch。
Composable 的架構設計原則
為了確保專案的整潔與一致性,建議遵循以下開發規範:
命名與目錄規範
- 目錄命名:統一將邏輯函數放置於
src/composables/資料夾下。 - 函數命名:檔案與函數名稱應以 use 作為開頭,並採用 小駝峰 (camelCase) 命名方式。
use 這個前綴不是語法要求,而是 給人看的提示:看到它就知道這個函式會用到響應式狀態與生命週期,必須在 setup 中呼叫。
設計核心準則
- 不直接操作 DOM:Composable 應專注於數據與邏輯。若需與 DOM 互動,應透過
ref()綁定或在生命週期中執行,例如:onMounted()。 - 邏輯與 UI 分離:Composable 只負責 怎麼做 ,而不負責 怎麼長 。
- 單一職責原則 (Single Responsibility):每個 Composable 應專注於單一領域,將同一個領域的邏輯聚合在一起。如: 取得多個使用者與單一使用者的資料就可以寫在一起。
專案結構範例
一個標準的 Vue 專案架構應如下所示:
src/
├─ composables/
│ ├─ useFetch.js # API 請求邏輯
│ ├─ useMouse.js # 滑鼠行為追蹤
│ └─ useAuth.js # 身分驗證管理
├─ App.vue
└─ main.js呼叫時機:必須在 setup 中同步呼叫
這是最常見的踩雷點。只要 Composable 內部註冊了 生命週期鉤子 或 watch,Vue 就得知道它屬於哪個元件,因此:
<script setup>
// ✅ 正確:在 setup 中同步呼叫
const { x, y } = useMouse();
// ❌ 失效:Vue 此時已經找不到對應的元件實體
function onClick() {
const { x, y } = useMouse();
}
</script>好消息是 生命週期鉤子可以註冊多次,所以一個元件同時使用五個 Composable 也不會互相干擾,各自管好自己的建立與清理。
Composable 與 Pinia 的分工
兩者都能複用邏輯,差別在於 狀態是誰的:
| Composable | Pinia | |
|---|---|---|
| 狀態份數 | 每次呼叫產生一份新的 | 全站共用同一份 |
| 適合的資料 | 各元件自己用的,例如:滑鼠座標、表單驗證 | 跨頁面共用的,例如:登入資訊、購物車 |
| 需不需要安裝 | 不用,就是一個函式 | 需要安裝並註冊外掛 |
一句話判斷:資料要不要被別的頁面看到? 不用,就寫成 Composable。
順帶一提:Composable 取代了 mixin
Vue 2 時代靠 mixin 複用邏輯,但它有兩個難以解決的問題:
- 來源不明:元件裡出現一個變數,卻不知道是哪個 mixin 帶進來的。
- 名稱衝突:兩個 mixin 都有
loading,後者會默默覆蓋前者。
Composable 用 明確的匯入 與 明確的回傳值 解決了這兩點,解構時還能自由改名,這也是 Vue 3 之後不再推薦 mixin 的原因。
結語:為什麼您該開始使用 Composable?
透過 Composable,我們能將複雜的業務邏輯從 .vue 檔案中解放出來,實現真正的 高內聚、低耦合 。這不僅符合現代前端開發的趨勢,更是從 Vue 菜鳥晉升為資深開發者的必經之路。
常見問題
Composable 就只是一般的函式嗎?
本質上是,差別在於它裡面會使用 Vue 的響應式 API 與生命週期,所以必須在 setup 期間同步呼叫。純粹計算用的工具函式不需要這些能力,放在 utils 就好。
Composable 與 Pinia 該用哪一個?
每次呼叫 Composable 都會產生一份 獨立狀態,適合各元件自己用的邏輯;Pinia 的 store 是 全站共用同一份,適合登入資訊或購物車這類跨頁面資料。
為什麼函式名稱一定要以 use 開頭?
這是社群慣例,用來提示這個函式會使用響應式狀態與生命週期,必須在 setup 中呼叫。一眼就能與普通工具函式區分開來。
Composable 是用來取代 mixin 的嗎?
是。mixin 的問題在於來源不明與屬性名稱衝突,Composable 透過明確的匯入與回傳值解決了這兩點,也能自由重新命名解構出來的變數。
Composable 可以在事件處理函式裡呼叫嗎?
若它內部註冊了 生命週期鉤子 或 watch,就必須在 setup 中同步呼叫,寫在按鈕事件裡會失效。單純回傳資料、沒用到生命週期的函式則不受此限。