Actions

Actions相当于组件中的 methods 。可以使用defineStore()中的actions属性来定义它们,并且它们非常适合定义业务逻辑:

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

getters一样,actions通过this来访问整个store实例,还有完整的类型支持(和自动补全功能)。与它们不同的是,actions可以是异步的,您可以在它们内部进行任何API的调用,甚至其他操作!下面是一个使用Mande的示例。请注意,只要你得到了一个Promise ,你使用什么样的库并不重要,您甚至可以使用原生的fetch函数(仅适用于浏览器端):

  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. // let the form component display the error
  16. return error
  17. }
  18. },
  19. },
  20. })

您也可以完全自由地设置任何您想要的参数并返回任何东西。当调用actions时,一切都会被自动推断出来!

actionsmethods调用类似:

  1. export default defineComponent({
  2. setup() {
  3. const main = useMainStore()
  4. // call the action as a method of the store
  5. main.randomizeCounter()
  6. return {}
  7. },
  8. })

访问其他 stores 的 actions

要使用另一个store,您可以直接在action内部使用它:

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

setup() 中的用法

您可以直接调用任何action作为store的方法:

  1. export default {
  2. setup() {
  3. const store = useStore()
  4. store.randomizeCounter()
  5. },
  6. }

Options API 中的用法

对于以下示例,您可以假设创建了以下store:

  1. // Example File Path:
  2. // ./src/stores/counterStore.js
  3. import { defineStore } from 'pinia'
  4. const useCounterStore = defineStore('counterStore', {
  5. state: () => ({
  6. counter: 0
  7. }),
  8. actions: {
  9. increment() {
  10. this.counter++
  11. }
  12. }
  13. })

使用 setup()

虽然Composition API并不适合所有人,但setup()钩子可以让Pinia更容易在Options API中使用。不需要额外的辅助函数!

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

不使用 setup()

如果您根本不想使用Composition API,您可以使用mapActions()辅助函数将actions属性映射为组件中的methods

  1. import { mapActions } from 'pinia'
  2. import { useCounterStore } from '../stores/counterStore'
  3. export default {
  4. methods: {
  5. // gives access to this.increment() inside the component
  6. // same as calling from store.increment()
  7. ...mapActions(useCounterStore, ['increment']),
  8. // same as above but registers it as this.myOwnName()
  9. ...mapActions(useCounterStore, { myOwnName: 'doubleCounter' }),
  10. },
  11. }

订阅 actions

可以使用store.$onAction()来观察actions及其结果。传递给它的回调函数在action本身之前执行。在处理promises之后,允许您在action resolves之后执行函数。类似地,onError允许你在action抛出或rejects时执行函数。这些对于在运行时跟踪错误很有用,类似于Vue文档中的这个技巧。

下面是一个在运行actions之前和resolve/reject之后记录日志的示例。

  1. const unsubscribe = someStore.$onAction(
  2. ({
  3. name, // name of the action
  4. store, // store instance, same as `someStore`
  5. args, // array of parameters passed to the action
  6. after, // hook after the action returns or resolves
  7. onError, // hook if the action throws or rejects
  8. }) => {
  9. // a shared variable for this specific action call
  10. const startTime = Date.now()
  11. // this will trigger before an action on `store` is executed
  12. console.log(`Start "${name}" with params [${args.join(', ')}].`)
  13. // this will trigger if the action succeeds and after it has fully run.
  14. // it waits for any returned promised
  15. after((result) => {
  16. console.log(
  17. `Finished "${name}" after ${
  18. Date.now() - startTime
  19. }ms.\nResult: ${result}.`
  20. )
  21. })
  22. // this will trigger if the action throws or returns a promise that rejects
  23. onError((error) => {
  24. console.warn(
  25. `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
  26. )
  27. })
  28. }
  29. )
  30. // manually remove the listener
  31. unsubscribe()

默认情况下,action订阅被绑定到添加它们的组件(如果store在组件的setup()中)。这就意味着,当组件被卸载时,它们将被自动删除。如果你想在组件卸载后保留它们,传true作为第二个参数,以将操作订阅与当前组件分离:

  1. export default {
  2. setup() {
  3. const someStore = useSomeStore()
  4. // this subscription will be kept after the component is unmounted
  5. someStore.$onAction(callback, true)
  6. // ...
  7. },
  8. }