跳至内容

获取器

获取器与 Store 状态的 计算属性 完全等效。它们可以在 defineStore() 中使用 getters 属性定义。它们接收 state 作为第一个参数,以 鼓励 使用箭头函数

js
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

大多数情况下,获取器只会依赖于状态。但是,它们可能需要使用其他获取器。因此,在定义常规函数时,我们可以通过 this 访问 整个 Store 实例但必须定义返回类型的类型(在 TypeScript 中)。这是由于 TypeScript 中的一个已知限制,并且 不会影响使用箭头函数定义的获取器或不使用 this 的获取器

ts
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // automatically infers the return type as a number
    doubleCount(state) {
      return state.count * 2
    },
    // the return type **must** be explicitly set
    doublePlusOne(): number {
      // autocompletion and typings for the whole store ✨
      return this.doubleCount + 1
    },
  },
})

然后,您可以直接在 Store 实例上访问获取器

vue
<script setup>
import { useCounterStore } from './counterStore'

const store = useCounterStore()
</script>

<template>
  <p>Double count is {{ store.doubleCount }}</p>
</template>

访问其他获取器

与计算属性一样,您可以组合多个获取器。通过 this 访问任何其他获取器。在这种情况下,您需要为获取器指定一个返回类型

ts
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.count * 2
    },
    doubleCountPlusOne(): number {
      return this.doubleCount + 1
    },
  },
})
js
// You can use JSDoc (https://jsdoc.node.org.cn/tags-returns.html) in JavaScript
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // type is automatically inferred because we are not using `this`
    doubleCount: (state) => state.count * 2,
    // here we need to add the type ourselves (using JSDoc in JS). We can also
    // use this to document the getter
    /**
     * Returns the count value times two plus one.
     *
     * @returns {number}
     */
    doubleCountPlusOne() {
      // autocompletion ✨
      return this.doubleCount + 1
    },
  },
})

向获取器传递参数

获取器 只是幕后 计算 属性,因此无法向它们传递任何参数。但是,您可以从 获取器 返回一个函数来接受任何参数

js
export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})

并在组件中使用

vue
<script setup>
import { storeToRefs } from 'pinia'
import { useUserListStore } from './store'

const userList = useUserListStore()
const { getUserById } = storeToRefs(userList)
// note you will have to use `getUserById.value` to access
// the function within the <script setup>
</script>

<template>
  <p>User 2: {{ getUserById(2) }}</p>
</template>

请注意,在执行此操作时,获取器不再被缓存。它们只是您调用的函数。但是,您可以在获取器本身内部缓存一些结果,这并不常见,但应该会提高性能

js
export const useStore = defineStore('main', {
  getters: {
    getActiveUserById(state) {
      const activeUsers = state.users.filter((user) => user.active)
      return (userId) => activeUsers.find((user) => user.id === userId)
    },
  },
})

访问其他 Store 的获取器

要使用另一个 Store 的获取器,您可以直接在 获取器 内部 使用它

js
import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

setup() 一起使用

您可以直接将任何获取器作为 Store 的属性访问(与状态属性完全相同)

vue
<script setup>
const store = useCounterStore()

store.count = 3
store.doubleCount // 6
</script>

与选项 API 一起使用

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

js
// Example File Path:
// ./src/stores/counter.js

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.count * 2
    },
  },
})

使用 setup()

虽然 Composition API 并非适合所有人,但 setup() 钩子可以使 Pinia 在选项 API 中更容易使用。无需额外的映射辅助函数!

vue
<script>
import { useCounterStore } from '../stores/counter'

export default defineComponent({
  setup() {
    const counterStore = useCounterStore()

    // **only return the whole store** instead of destructuring
    return { counterStore }
  },
  computed: {
    quadrupleCounter() {
      return this.counterStore.doubleCount * 2
    },
  },
})
</script>

这在将组件从选项 API 迁移到 Composition API 时很有用,但 应该只是一个迁移步骤。始终尝试不要在同一个组件中混合两种 API 样式。

无需 setup()

您可以使用与 状态的上一节 中使用的相同 mapState() 函数来映射到获取器

js
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counter'

export default {
  computed: {
    // gives access to this.doubleCount inside the component
    // same as reading from store.doubleCount
    ...mapState(useCounterStore, ['doubleCount']),
    // same as above but registers it as this.myOwnName
    ...mapState(useCounterStore, {
      myOwnName: 'doubleCount',
      // you can also write a function that gets access to the store
      double: (store) => store.doubleCount,
    }),
  },
}