Skip to content

action

Action 相当于组件中的method

定义action

可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择。

ts
export const useCounterStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++
    },
    randomizeCounter() {
      this.count = Math.round(100 * Math.random())
    },
  },
})

类似getter,action 也可通过 this 访问整个 store 实例,并支持完整的类型标注(以及自动补全✨)不同的是,action 可以是异步的,你可以在它们里面 await 调用任何 API,以及其他 action!

调用action

setup API

vue
<script setup>
const store = useCounterStore()
// 将 action 作为 store 的方法进行调用
store.randomizeCounter()
</script>
<template>
  <!-- 即使在模板中也可以 -->
  <button @click="store.randomizeCounter()">Randomize</button>
</template>

option API

如果你不喜欢使用组合式 API,你也可以使用 mapActions() 辅助函数将 action 属性映射为你组件中的方法。

ts
import { mapActions } from 'pinia'
import { useCounterStore } from '../stores/counter'

export default {
  methods: {
    // 访问组件内的 this.increment()
    // 与从 store.increment() 调用相同
    ...mapActions(useCounterStore, ['increment'])
    // 与上述相同,但将其注册为this.myOwnName()
    ...mapActions(useCounterStore, { myOwnName: 'increment' }),
  },
}

访问其他 store 的 action

想要使用另一个 store 的话,那你直接在 action 中调用就好了:

ts
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')
      }
    },
  },
})

私有方法

将方法声明在store外部即可创建私有方法,只供store内部使用。

因为 thisactions 里就是当前 store 实例,所以action函数可以直接访问 this.state。 但是私有方法的this并不是state,我们可以将 state传入私有方法:

ts
function _formatId(id: string, state: { id: string }) {
  console.log('old id:', state.id)
  return id.trim().toUpperCase()
}

export const useUserStore = defineStore('user', {
  state: () => ({
    id: '',
  }),
  actions: {
    setId(id: string) {
      this.id = _formatId(id, this)
    }
  }
})