Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。 如果您熟悉 Composition API,您可能会认为您已经可以通过一个简单的 export const state = reactive({})
来共享全局状态。但是这样在SPA页面中还行,在SSR应用中则会使您的应用程序暴露于安全漏洞。
Vuex: State、Gettes、Mutations(同步)、Actions(异步)
Pinia: State、Gettes、Actions(同步异步都支持)
Tips: 从 2022-02-07 在 Vue 3 被设置为默认版本开始, Pinia 已正式被官方推荐作为全局状态管理的工具。
yarn add pinia
# or with npm
npm install pinia
查看你的 package.json ,看看里面的 dependencies
是否成功加入了 Pinia 和它的版本号(下方是示例代码,以实际安装的最新版本号为准):
{
"dependencies": {
"pinia": "^2.0.11",
},
}
以 Vue3 + TypeScript
为例
打开 src/main.ts
文件,添加下面那两行有注释的新代码:
import { createApp } from 'vue'
import { createPinia } from 'pinia' // 导入 Pinia
import App from '@/App.vue'
createApp(App)
.use(createPinia()) // 启用 Pinia
.mount('#app')
在上面的片段中,你将Pinia添加到Vue项目中,这样你就可以在你的代码中使用Pinia的全局对象。
在 store 目录下创建一个 users.ts
为例,我们先定义并导出一个名为 users
的模块
// /src/store/user.ts
// 想要使用必须先引入 defineStore;
import { defineStore } from 'pinia';
// 这里我们使用的是es6 的模块化规范进行导出的。
// defineStore 方法有两个参数,第一个参数是模块化名字
// 第二个参数是选项,对象里面有三个属性,相比于vuex 少了一个 mutations.
export const useStore = defineStore('users', {
state(){ // 存放的就是模块的变量
return {
count: 1,
arr: []
}
},
getters:{ // 相当于vue里面的计算属性,可以缓存数据
},
actions:{ // 可以通过actions 方法,改变 state 里面的值。
}
})
我们需要知道 Store 是使用 defineStore()
定义的,并且它需要一个唯一名称,作为第一个参数传递。defineStore
函数接收两个参数name、options:
前面我们创建了一个store,假如我们要在App.vue里面使用它,该如何使用呢?我们在页面中如何访问 state 里的属性 count?
/src/App.vue
{{ user_store.count }}
上述代码就可以轻松拿到store内的属性值count。
但是,请注意,store
是一个用reactive
包裹的对象,就像setup
中的props
一样,我们不能对其进行解构。这样拿到的数据不是响应式的。
为了从 Store 中提取属性同时保持其响应式,您需要使用storeToRefs()。 它将为任何响应式属性创建 refs。 当您仅使用 store 中的状态但不调用任何操作时,这很有用:
{{ count }}
/src/App.vue
{{ user_store.count }}
修改状态:
store
实例访问状态来直接读取和写入状态;重置状态:可以通过调用 store 上的 $reset()
方法将状态 重置 到其初始值。
有缓存功能。如下在页面中多次使用,第一次会调用 getters,数据没有改变的情况下之后会读取缓存。
// /src/store/user.ts
import { defineStore } from 'pinia';
export const useStore = defineStore('users', {
state(){ // 存放的就是模块的变量
return {
name: "回忆哆啦没有A梦",
age: 25,
sex: "男",
}
},
getters: {
// 方法一,接收一个可选参数 state
getAddAge(state){
console.log('调用了') // 页面中使用了多次,这里只会执行一次,然后缓存起来了
return state.age+ 1
},
// 方法二,不传参数,使用 this
// 但是必须指定函数返回值的类型,否则类型推导不出来
getAddAge(): number{
return this.age+ 1
}
},
actions: {
},
})
我们在App.vue中想要调用getters内的方法:
// /src/App.vue
新年龄:{{ user_store.getAddAge }}
添加一个actions方法,修改state。
// /src/store/user.ts
import { defineStore } from 'pinia';
export const useStore = defineStore('users', {
state(){ // 存放的就是模块的变量
return {
name: "回忆哆啦没有A梦",
age: 25,
sex: "男",
}
},
getters: {
},
actions: {
saveName(name: string) {
this.name = name;
},
},
})
上段代码中我们定义了一个非常简单的actions方法changeState,在实际场景中,该方法可以是任何逻辑,比如发送请求、存储token等等。大家把actions方法当作一个普通的方法即可,特殊之处在于该方法内部的this指向的是当前store。
我们在App.vue中想要调用actions内的方法:
// /src/App.vue
{{ user_store.count }}
如果还有兴趣学习pinia的其它特点,比如插件、订阅等等,可以移步官网:pinia官网。