Pinia Action

2023-09-28 14:45 更新

Action 相當(dāng)于組件中的 method。它們可以通過 defineStore() 中的 actions 屬性來定義,并且它們也是定義業(yè)務(wù)邏輯的完美選擇。

  1. export const useCounterStore = defineStore('main', {
  2. state: () => ({
  3. count: 0,
  4. }),
  5. actions: {
  6. increment() {
  7. this.count++
  8. },
  9. randomizeCounter() {
  10. this.count = Math.round(100 * Math.random())
  11. },
  12. },
  13. })

類似 getter,action 也可通過 this 訪問整個 store 實(shí)例,并支持完整的類型標(biāo)注(以及自動補(bǔ)全?)不同的是,action 可以是異步的,你可以在它們里面 await 調(diào)用任何 API,以及其他 action!下面是一個使用 Mande 的例子。請注意,你使用什么庫并不重要,只要你得到的是一個Promise,你甚至可以 (在瀏覽器中) 使用原生 fetch 函數(shù):

  1. import { mande } from 'mande'
  2. const api = mande('/api/users')
  3. export const useUsers = defineStore('users', {
  4. state: () => ({
  5. userData: null,
  6. // ...
  7. }),
  8. actions: {
  9. async registerUser(login, password) {
  10. try {
  11. this.userData = await api.post({ login, password })
  12. showTooltip(`Welcome back ${this.userData.name}!`)
  13. } catch (error) {
  14. showTooltip(error)
  15. // 讓表單組件顯示錯誤
  16. return error
  17. }
  18. },
  19. },
  20. })

你也完全可以自由地設(shè)置任何你想要的參數(shù)以及返回任何結(jié)果。當(dāng)調(diào)用 action 時,一切類型也都是可以被自動推斷出來的。

Action 可以像函數(shù)或者通常意義上的方法一樣被調(diào)用:

  1. <script setup>
  2. const store = useCounterStore()
  3. // 將 action 作為 store 的方法進(jìn)行調(diào)用
  4. store.randomizeCounter()
  5. </script>
  6. <template>
  7. <!-- 即使在模板中也可以 -->
  8. <button @click="store.randomizeCounter()">Randomize</button>
  9. </template>

訪問其他 store 的 action

想要使用另一個 store 的話,那你直接在 action 中調(diào)用就好了:

  1. import { useAuthStore } from './auth-store'
  2. export const useSettingsStore = defineStore('settings', {
  3. state: () => ({
  4. preferences: null,
  5. // ...
  6. }),
  7. actions: {
  8. async fetchUserPreferences() {
  9. const auth = useAuthStore()
  10. if (auth.isAuthenticated) {
  11. this.preferences = await fetchPreferences()
  12. } else {
  13. throw new Error('User must be authenticated')
  14. }
  15. },
  16. },
  17. })

使用選項(xiàng)式 API 的用法

在下面的例子中,你可以假設(shè)相關(guān)的 store 已經(jīng)創(chuàng)建了:

  1. // 示例文件路徑:
  2. // ./src/stores/counter.js
  3. import { defineStore } from 'pinia'
  4. const useCounterStore = defineStore('counter', {
  5. state: () => ({
  6. count: 0
  7. }),
  8. actions: {
  9. increment() {
  10. this.count++
  11. }
  12. }
  13. })

使用 setup()

雖然并不是每個開發(fā)者都會使用組合式 API,但 setup() 鉤子依舊可以使 Pinia 在選項(xiàng)式 API 中更易用。并且不需要額外的映射輔助函數(shù)!

  1. <script>
  2. import { useCounterStore } from '../stores/counter'
  3. export default defineComponent({
  4. setup() {
  5. const counterStore = useCounterStore()
  6. return { counterStore }
  7. },
  8. methods: {
  9. incrementAndPrint() {
  10. this.counterStore.increment()
  11. console.log('New Count:', this.counterStore.count)
  12. },
  13. },
  14. })
  15. </script>

不使用 setup()

如果你不喜歡使用組合式 API,你也可以使用 mapActions() 輔助函數(shù)將 action 屬性映射為你組件中的方法。

  1. import { mapActions } from 'pinia'
  2. import { useCounterStore } from '../stores/counter'
  3. export default {
  4. methods: {
  5. // 訪問組件內(nèi)的 this.increment()
  6. // 與從 store.increment() 調(diào)用相同
  7. ...mapActions(useCounterStore, ['increment'])
  8. // 與上述相同,但將其注冊為this.myOwnName()
  9. ...mapActions(useCounterStore, { myOwnName: 'increment' }),
  10. },
  11. }

訂閱 action

你可以通過 store.$onAction() 來監(jiān)聽 action 和它們的結(jié)果。傳遞給它的回調(diào)函數(shù)會在 action 本身之前執(zhí)行。after 表示在 promise 解決之后,允許你在 action 解決后執(zhí)行一個回調(diào)函數(shù)。同樣地,onError 允許你在 action 拋出錯誤或 reject 時執(zhí)行一個回調(diào)函數(shù)。這些函數(shù)對于追蹤運(yùn)行時錯誤非常有用,類似于Vue docs 中的這個提示。

這里有一個例子,在運(yùn)行 action 之前以及 action resolve/reject 之后打印日志記錄。

  1. const unsubscribe = someStore.$onAction(
  2. ({
  3. name, // action 名稱
  4. store, // store 實(shí)例,類似 `someStore`
  5. args, // 傳遞給 action 的參數(shù)數(shù)組
  6. after, // 在 action 返回或解決后的鉤子
  7. onError, // action 拋出或拒絕的鉤子
  8. }) => {
  9. // 為這個特定的 action 調(diào)用提供一個共享變量
  10. const startTime = Date.now()
  11. // 這將在執(zhí)行 "store "的 action 之前觸發(fā)。
  12. console.log(`Start "${name}" with params [${args.join(', ')}].`)
  13. // 這將在 action 成功并完全運(yùn)行后觸發(fā)。
  14. // 它等待著任何返回的 promise
  15. after((result) => {
  16. console.log(
  17. `Finished "${name}" after ${
  18. Date.now() - startTime
  19. }ms.\nResult: ${result}.`
  20. )
  21. })
  22. // 如果 action 拋出或返回一個拒絕的 promise,這將觸發(fā)
  23. onError((error) => {
  24. console.warn(
  25. `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
  26. )
  27. })
  28. }
  29. )
  30. // 手動刪除監(jiān)聽器
  31. unsubscribe()

默認(rèn)情況下,action 訂閱器會被綁定到添加它們的組件上(如果 store 在組件的 setup() 內(nèi))。這意味著,當(dāng)該組件被卸載時,它們將被自動刪除。如果你想在組件卸載后依舊保留它們,請將 true 作為第二個參數(shù)傳遞給 action 訂閱器,以便將其從當(dāng)前組件中分離:

  1. <script setup>
  2. const someStore = useSomeStore()
  3. // 此訂閱器即便在組件卸載之后仍會被保留
  4. someStore.$onAction(callback, true)
  5. </script>
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號