Pinia Action

2023-09-28 14:45 更新

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>

訪問其他 store 的 action

想要使用另一個(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')
      }
    },
  },
})

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

在下面的例子中,你可以假設(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' }),
  },
}

訂閱 action

你可以通過 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>
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)