• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • defineStore

    我们得知道 Store 是用defineStore()定义的,它的第一个参数要求是一个独一无二的名字:

    import { defineStore } from 'pinia'
    
    // 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
    // 第一个参数是你的应用中 Store 的唯一 ID
    export const useStore = defineStore('main', {
      // 其他配置...
    })
    

    这个名字,也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。为了养成习惯性的用法,将返回的函数命名为use...是一个符合组合式函数风格的约定。

    defineStore()的第二个参数可接受两类值::Setup函数或Options对象。


    Option 式

    与 Vue 的 Options API(选项式 API)类似,我们也可以传入一个带有stateactionsgetters属性的Options对象。

    export const useCounterStore = defineStore('counter', {
      state: () => ({ count: 0, name: 'Eduardo' }),
      getters: {
        doubleCount: (state) => state.count * 2,
      },
      actions: {
        increment() {
          this.count++
        },
      },
    })
    

    你可以认为state是 Store 的数据(data),getters是 Store 的计算属性(computed),而actions则是 Store 的方法(methods)。

    为方便上手使用,Option Store 应尽可能直观简单。


    Setup 式

    还有另一种可能的语法来定义 Store。与 Vue Composition API 的Setup函数类似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

    export const useCounterStore = defineStore('counter', () => {
    
      const count = ref(0)
      const name = ref('Eduardo')
    
      const doubleCount = computed(() => count.value * 2)
    
      function increment() {
        count.value++
      }
    
      return { count, name, doubleCount, increment }
    })
    

    Setup式中:ref()成为state属性,computed()变成gettersfunction()变成actions

    • Setup式 Store 比Options式 Store,带来更多的灵活性,因为您可以在 Store 中,创建观察者并自由使用任何可组合的。但是,请记住,使用任何可组合,会得更复杂的 SSR。
    • 与 Vue 的 Composition API 和 Option API一样,选择你觉得最舒服的一个。如果您不确定,请先尝试 Option 式 Store。


    使用Store

    虽然我们前面定义了一个 store(名称为类似use…Store的格式),但在组件setup()中,调用useStore()之前,store 实例是不会被创建的:

    import { useCounterStore } from '@/stores/counter'
    
    export default {
      setup() {
        const store = useCounterStore()
    
        return {
          // 为了能在模板中使用它,你可以返回整个 Store 实例
          store,
        }
      },
    }
    

    你可以定义任意多的 store,但为了让使用 pinia 的益处最大化(比如允许构建工具自动进行代码分割以及 TypeScript 推断),你应该在不同的文件中去定义 store。

    如果你还不会使用 setup 组件,你也可以通过映射辅助函数来使用 Pinia。

    一旦 store 被实例化,你可以直接访问在 store 的 state、getters 和 actions 中定义的任何属性。我们将在后续章节继续了解这些细节,目前自动补全将帮助你使用相关属性。


    ⚠注意,如果这 Store 是一个用reactive包裹的对象,这意味着不需要在getter之后写.value。就像setup()中的props一样,我们不能解构它,因为会丧失响应性:

    export default defineComponent({
      setup() {
        const store = useCounterStore()
        // ❌ 这将无法生效,因为它破坏了响应性
        // 这与从 `props` 中解构是一样的
        const { name, doubleCount } = store
    
        name // "Eduardo"
        doubleCount // 0
    
        setTimeout(() => {
          store.increment()
        }, 1000)
    
        return {
          // 始终是 "Eduardo"
          name,
          // will always be 0
          doubleCount,
          // will also always be 0
          doubleNumber: store.doubleCount,
    
          // ✅ 个将是响应式的
          doubleValue: computed(() => store.doubleCount),
        }
      },
    })
    

    为了从 Store 中提取属性,同时保持其响应性,您需要使用storeToRefs(),它将为每个响应性属性创建引用。当你只使用 Store 的状态而不调用任何action时,它会非常有用。

    ⚠注意,您可以直接从 Store 中解构action,因为它们也绑定到 Store 本身:

    import { storeToRefs } from 'pinia'
    
    export default defineComponent({
      setup() {
        const store = useCounterStore()
        // `name` and `doubleCount` 都是响应式 refs
        // 这也将为由插件添加的属性创建 refs
        //同时会跳过任何 action 或非响应式(非 ref/响应式)属性
        const { name, doubleCount } = storeToRefs(store)
        // 名为 increment 的 action 可以直接提取
        const { increment } = store
    
        return {
          name,
          doubleCount,
          increment,
        }
      },
    })
    

    上篇:Pinia 入门安装

    下篇:state