Action 相當(dāng)于組件中的 method。它們可以通過 defineStore()
中的 actions
屬性來定義,并且它們也是定義業(yè)務(wù)邏輯的完美選擇。
export const useCounterStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.round(100 * Math.random())
},
},
})
類似 getter,action 也可通過 this
訪問整個(gè) store 實(shí)例,并支持完整的類型標(biāo)注(以及自動(dòng)補(bǔ)全?)。不同的是,action
可以是異步的,你可以在它們里面 await
調(diào)用任何 API,以及其他 action!下面是一個(gè)使用 Mande 的例子。請(qǐng)注意,你使用什么庫(kù)并不重要,只要你得到的是一個(gè)Promise
,你甚至可以 (在瀏覽器中) 使用原生 fetch
函數(shù):
import { mande } from 'mande'
const api = mande('/api/users')
export const useUsers = defineStore('users', {
state: () => ({
userData: null,
// ...
}),
actions: {
async registerUser(login, password) {
try {
this.userData = await api.post({ login, password })
showTooltip(`Welcome back ${this.userData.name}!`)
} catch (error) {
showTooltip(error)
// 讓表單組件顯示錯(cuò)誤
return error
}
},
},
})
你也完全可以自由地設(shè)置任何你想要的參數(shù)以及返回任何結(jié)果。當(dāng)調(diào)用 action 時(shí),一切類型也都是可以被自動(dòng)推斷出來的。
Action 可以像函數(shù)或者通常意義上的方法一樣被調(diào)用:
<script setup>
const store = useCounterStore()
// 將 action 作為 store 的方法進(jìn)行調(diào)用
store.randomizeCounter()
</script>
<template>
<!-- 即使在模板中也可以 -->
<button @click="store.randomizeCounter()">Randomize</button>
</template>
想要使用另一個(gè) store 的話,那你直接在 action 中調(diào)用就好了:
import { useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
state: () => ({
preferences: null,
// ...
}),
actions: {
async fetchUserPreferences() {
const auth = useAuthStore()
if (auth.isAuthenticated) {
this.preferences = await fetchPreferences()
} else {
throw new Error('User must be authenticated')
}
},
},
})
在下面的例子中,你可以假設(shè)相關(guān)的 store 已經(jīng)創(chuàng)建了:
// 示例文件路徑:
// ./src/stores/counter.js
import { defineStore } from 'pinia'
const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++
}
}
})
setup()
雖然并不是每個(gè)開發(fā)者都會(huì)使用組合式 API,但 setup()
鉤子依舊可以使 Pinia 在選項(xiàng)式 API 中更易用。并且不需要額外的映射輔助函數(shù)!
<script>
import { useCounterStore } from '../stores/counter'
export default defineComponent({
setup() {
const counterStore = useCounterStore()
return { counterStore }
},
methods: {
incrementAndPrint() {
this.counterStore.increment()
console.log('New Count:', this.counterStore.count)
},
},
})
</script>
setup()
如果你不喜歡使用組合式 API,你也可以使用 mapActions()
輔助函數(shù)將 action 屬性映射為你組件中的方法。
import { mapActions } from 'pinia'
import { useCounterStore } from '../stores/counter'
export default {
methods: {
// 訪問組件內(nèi)的 this.increment()
// 與從 store.increment() 調(diào)用相同
...mapActions(useCounterStore, ['increment'])
// 與上述相同,但將其注冊(cè)為this.myOwnName()
...mapActions(useCounterStore, { myOwnName: 'increment' }),
},
}
你可以通過 store.$onAction()
來監(jiān)聽 action 和它們的結(jié)果。傳遞給它的回調(diào)函數(shù)會(huì)在 action 本身之前執(zhí)行。after
表示在 promise 解決之后,允許你在 action 解決后執(zhí)行一個(gè)回調(diào)函數(shù)。同樣地,onError
允許你在 action 拋出錯(cuò)誤或 reject 時(shí)執(zhí)行一個(gè)回調(diào)函數(shù)。這些函數(shù)對(duì)于追蹤運(yùn)行時(shí)錯(cuò)誤非常有用,類似于Vue docs 中的這個(gè)提示。
這里有一個(gè)例子,在運(yùn)行 action 之前以及 action resolve/reject 之后打印日志記錄。
const unsubscribe = someStore.$onAction(
({
name, // action 名稱
store, // store 實(shí)例,類似 `someStore`
args, // 傳遞給 action 的參數(shù)數(shù)組
after, // 在 action 返回或解決后的鉤子
onError, // action 拋出或拒絕的鉤子
}) => {
// 為這個(gè)特定的 action 調(diào)用提供一個(gè)共享變量
const startTime = Date.now()
// 這將在執(zhí)行 "store "的 action 之前觸發(fā)。
console.log(`Start "${name}" with params [${args.join(', ')}].`)
// 這將在 action 成功并完全運(yùn)行后觸發(fā)。
// 它等待著任何返回的 promise
after((result) => {
console.log(
`Finished "${name}" after ${
Date.now() - startTime
}ms.\nResult: ${result}.`
)
})
// 如果 action 拋出或返回一個(gè)拒絕的 promise,這將觸發(fā)
onError((error) => {
console.warn(
`Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
)
})
}
)
// 手動(dòng)刪除監(jiān)聽器
unsubscribe()
默認(rèn)情況下,action 訂閱器會(huì)被綁定到添加它們的組件上(如果 store 在組件的 setup()
內(nèi))。這意味著,當(dāng)該組件被卸載時(shí),它們將被自動(dòng)刪除。如果你想在組件卸載后依舊保留它們,請(qǐng)將 true
作為第二個(gè)參數(shù)傳遞給 action 訂閱器,以便將其從當(dāng)前組件中分離:
<script setup>
const someStore = useSomeStore()
// 此訂閱器即便在組件卸載之后仍會(huì)被保留
someStore.$onAction(callback, true)
</script>
更多建議: