defineStore - Pinia(状态管理)
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)类似,我们也可以传入一个带有state
、actions
和getters
属性的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()变成getters
,function()变成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, } }, })
鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com
图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!