概述
在vue3中,项目里面使用状态管理,有两种选择,Pinia 和 Vuex 都是 Vue 的状态管理库,官方更加推荐pinia,因为其API的使用更加简洁方便,我们在项目里面通过hook方式快速方便的接入。
pinia示例
pinia提供两种store的使用方式
Option Store
与 Vue 的选项式 API 类似,我们也可以传入一个带有 state
、actions
与 getters
属性的 Option 对象
js
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0, name: 'Eduardo' }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
setup Store(推荐)
也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
js
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 Store的方式实现一个类似的我们自己的store,因为这种方式更加符合组合式API的特性,我们使用和编写对应代码也更加简单方便,核心为闭包函数,不了解js闭包函数的,可以先学习下相关概念。主要应用闭包函数如下特性:
- 记忆环境:闭包可以记住创建时的词法环境
- 保持变量:闭包可以让局部变量在函数执行完后仍然保持在内存中
- 私有性:闭包可以用来创建私有变量和方法
效果

具体实现
定义store
新建store/useCounter.js
js
import { computed, ref } from "vue";
// 定义store
export const useCounterStore = defineStore(() => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubleCount, increment };
});
// 闭包函数缓存
function defineStore(fn) {
let state = null
return () => {
if (!state) {
state = fn()
}
return state
}
}
使用
新增Test.vue组件,导入store使用
js
<script setup lang="ts">
import { useCounterStore } from "../hook/useCounter";
const { count, doubleCount, increment } = useCounterStore();
</script>
<template>
<div>
<h2>Test组件</h2>
<p>count:{{ count }}</p>
<p>doubleCount:{{ doubleCount }}</p>
<button @click="increment">递增</button>
</div>
</template>
APP中引入测试组件
js
<template>
<Test></Test>
<Test></Test>
<Test></Test>
</template>
总结
如上所示,我们自定义的store可以和pinia的setup Store一样的用法,唯一不同在于,pinia第一个参数用作store的id使用,我们自己使用时没有用到了,官方Pinia 将用它来连接 store 和 devtools,因此本地我们自己实现就没必要了,实现核心在于闭包函数,多数工具库中是非常常见的用法。