昨天我們已經在魔法書院裡完成了 Pinia 的 Composition API 咒語。
今天要召喚另一種魔法陣:Options API 風格!
在開始之前,先釐清一個重點:
Pinia 並沒有「setter」這個東西。
在 Pinia 的世界裡,寫入/更新 state 的行為,是透過 function 來完成的:
function
(例如 setOrdersJson
)。actions: {}
裡的方法(例如 replaceAllOrders
)。你可以把它們視為 Pinia 的 setter 行為,但它們不是 computed 的 set()
。
Vue 的 computed.set()
是 Vue 本身的能力,而不是 Pinia 的;在複雜邏輯下更建議用 function/action 來承擔。
因為 Pinia 想要照顧不同的魔法師:
特性 | Composition API | Options API |
---|---|---|
學習曲線 | 需要熟悉 Vue 3 Composition API | 類似 Vuex,容易上手 |
語法風格 | 函數式,更靈活 | 物件式,結構化 |
TypeScript | 更好的型別推斷 | 需要額外設定 |
適用場景 | 複雜邏輯、現代開發 | 團隊協作、傳統開發 |
程式碼組織 | 邏輯可自由組合 | 結構清晰分離 |
其實可以考古一下
從前的大老們都是使用vuex但是現在改用pinia這樣
資訊技術本身就是會隨時間演進改變的~
所以基本上還是追隨公司的慣用風格跟框架來做調整~ 還有使用
這邊可以幫大家複習一下
Vuex 概念 | Pinia Options API | Pinia Composition API |
---|---|---|
state |
state: () => ({}) |
const state = ref() |
getters |
getters: {} |
const computed = computed() |
mutations |
❌ 不需要 | ❌ 不需要 |
actions |
actions: {} |
function action() {} |
modules |
多個 store | 多個 store |
為什麼 Vuex 需要 mutations
?
在 Vuex 中,mutations 是唯一能夠同步修改 state 的方式。
一般流程是:
dispatch action → (可包含非同步操作) → commit mutation → 改變 state
// Day 12 的寫法 - Composition API
export const useOrderStore = defineStore('orders', () => {
const orders = ref([])
const loading = ref(false)
const error = ref('')
const ordersJson = computed(() => JSON.stringify(orders.value, null, 2))
function setOrdersJson(txt) {
orders.value = parsed
}
return { orders, loading, error, ordersJson, setOrdersJson }
})
// Day 12.5 的寫法 - Options API
export const useOrderStore = defineStore('orders', {
state: () => ({
orders: [],
loading: false,
error: ''
}),
getters: {
ordersJson: (state) => JSON.stringify(state.orders, null, 2)
},
actions: {
setOrdersJson(txt) {
this.orders = parsed
}
}
})
其實有了概念交互對照就很快
概念 | Options API | Composition API |
---|---|---|
狀態 | state: () => ({}) |
const state = ref() |
計算屬性 | getters: {} |
const computed = computed() |
動作(setter 行為) | actions: {} |
function action() {} |
存取狀態 | this.state |
state.value |
語法 | 物件結構 | 函數回傳 |
// Day 12 - Composition API 風格
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { OrderService } from '../services/orderService'
export const useOrderStore = defineStore('orders', () => {
// State
const orders = ref([])
const loading = ref(false)
const error = ref('')
// Getters
const summaryRows = computed(() => {
const m = new Map()
for (const o of orders.value) {
const key = `${o.drink}|${o.sweetness}|${o.ice}`
m.set(key, (m.get(key) || 0) + 1)
}
return Array.from(m.entries()).map(([key, count]) => {
const [drink, sweetness, ice] = key.split('|')
return { key, drink, sweetness, ice, count }
})
})
const ordersJson = computed(() => {
return JSON.stringify(orders.value, null, 2)
})
// Actions (setter 行為)
function setOrdersJson(txt) {
try {
const parsed = JSON.parse(txt)
// 驗證邏輯...
orders.value = parsed
error.value = ''
} catch (e) {
error.value = '匯入訂單 JSON 失敗: ' + e.message
}
}
async function loadOrders() {
try {
loading.value = true
error.value = ''
const data = await OrderService.list()
orders.value = data
} catch (err) {
error.value = '載入訂單失敗: ' + err.message
} finally {
loading.value = false
}
}
return {
orders, loading, error,
summaryRows, ordersJson,
setOrdersJson, loadOrders
}
})
// Day 12.5 - Options API 風格
import { defineStore } from 'pinia'
import { OrderService } from '../services/orderService'
export const useOrderStore = defineStore('orders', {
state: () => ({
orders: [],
loading: false,
error: ''
}),
getters: {
summaryRows: (state) => {
const m = new Map()
for (const o of state.orders) {
const key = `${o.drink}|${o.sweetness}|${o.ice}`
m.set(key, (m.get(key) || 0) + 1)
}
return Array.from(m.entries()).map(([key, count]) => {
const [drink, sweetness, ice] = key.split('|')
return { key, drink, sweetness, ice, count }
})
},
ordersJson: (state) => {
return JSON.stringify(state.orders, null, 2)
}
},
actions: {
// setter 行為
setOrdersJson(txt) {
try {
const parsed = JSON.parse(txt)
this.orders = parsed
this.error = ''
} catch (e) {
this.error = '匯入訂單 JSON 失敗: ' + e.message
}
},
async loadOrders() {
try {
this.loading = true
this.error = ''
const data = await OrderService.list()
this.orders = data
} catch (err) {
this.error = '載入訂單失敗: ' + err.message
} finally {
this.loading = false
}
}
}
})
例如:
setOrdersJson(txt)
replaceAllOrders(newOrders)
這些 function 都是 setter 行為。
👉 Vue 的 computed.set()
是 Vue 的能力,而不是 Pinia 的。
computed.set()
。actions: {}
裡的方法,就是 setter。Component → 呼叫 store 的 action。
Store → action(function)負責 setter 行為。
Action → 修改 state。
State 改變 → Vue 響應式機制觸發 UI 更新。
✨小結:
Pinia 的魔法核心,就是「用 function 來改變 state」。
至於你想寫在卷軸(Options API),還是用靈活的咒語(Composition API),就看你的團隊習慣與專案需求囉!