Pinia
是一个 Vue
的存储库, Pinia
最初是一个实验,它的作者是Vue.js
核心团队的成员,本来是为了测试Vuex5
提案而出现的,在2019年11月
左右重新设计的Vue
状态管理以适用于 Composition API
,它不但支持Vue3
也支持Vue2
的options API
,也是下一代的轻量级状态管理库。
Pinia是vue的官方核心开发成员开发的,天然对vue是支持的,设计也非常接近vuex5的提案,甚至vuex5的部分灵感都是来自于pinia,目前你就可以把它当做是vuex5来看。
Vuex
既然说是Vuex5
,先来看看vuex4
的问题:
1、改变一个state
的值,如果是同步更新需要mutations
,异步的时候需要在actions
2、给Vuex
的state
添加typescript
,需要自定义复杂的类型来支持ts
3、把vue
想中的state
分成多个部分,就需要用到 module
4、从vue3
开始。getters
的结果不会像计算属性那样缓存了
5、vuex4.X
有一些与类型安全相关的问题
Pinia
如下总结了Pinia
与Vuex
来说有哪些优势:
1、Vue2
和Vue3
都支持,支持两种语法创建 Store:Options Api
和 Composition Api
2、pinia
中只有state、getter、action
,抛弃了Vuex
中的Mutation
3、pinia
中action
支持同步和异步,Vuex
不支持
4、良好的Typescript
支持
5、无需再创建各个模块嵌套了,Vuex
中如果数据过多,通常分模块来进行管理,稍显麻烦,而pinia
中可以构建多个store
,打包管理会自动拆分
6 .体积非常小,只有1KB
左右。 pinia
支持插件来扩展自身功能。 支持服务端渲染。
Vuex
的代码分割: 打包时,vuex
会把3个store
合并打包,当首页用到Vuex
时,这个包会引入到首页一起打包,最后输出1个js chunk
。这样的问题是,其实首页只需要其中1个store
,但其他2个无关的store
也被打包进来,造成资源浪费。
Pinia
的代码分割: 打包时,Pinia
会检查引用依赖,当首页用到main store
,打包只会把用到的store
和页面合并输出1个js chunk
,其他2个store
不耦合在其中。Pinia
能做到这点,是因为它的设计就是store
分离的,解决了项目的耦合问题。
Pinia使用
安装
$ yarn add pinia
# 或者使用npm
$ npm install pinia
使用示例
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
// 创建Pinia实例
const pinia = createPinia()
// 实例化 Vue
createApp(App)
.use(pinia) // 挂载到Vue根实例上
.mount('#app') // 挂载在真实 DOM
store
的定义是通过 defineStore
函数,它需要一个唯一的名称,该名称可以作为第一个参数传递,也可以用 id
熟悉传递。
该 store
是一个 reactive
对象,所以不需要 “.value”
,也不能对其进行解构使用,否则失去响应性。如果一定要对其进行解构使用,可以使用 storeToRefs
,类似 vue3
中的 toRefs
。
操作store
1、直接修改
2、批量修改 借助$patch
方法
3、批量修改 依然借助$patch
方法 利用回调函数处理数组等
4、整个替换 利用$state
方法
5、重置 利用$reset
方法
监听
可以通过$subscribe()store
的方法观察状态及其变化,类似于 Vuex
的 subscribe
方法。该方法的第一个参数接受一个回调函数,该函数可以在 state 变化时触发。
- events : 是这次state改变的具体数据,包括改变前的值和改变后的值等等数据
- storeId :是当前store的id
- type:type表示这次变化是通过什么产生的,主要有三个分别是
- “direct” :通过
action
变化的 - ”patch object“ :通过
$patch
传递对象的方式改变的 - “patch function” :通过
$patch
传递函数的方式改变的
- “direct” :通过
store.$subscribe()
的方法的第二个参数options
对象,是各种配置参数,包括detached
属性,其值是一个布尔值,默认是 false
, 正常情况下,当 订阅所在的组件被卸载时,订阅将被停止删除,如果设置detached
值为 true
时,即使所在组件被卸载,订阅依然可以生效。
取消监听
mainStore.$subscribe
返回的值(即上方示例的 subscribe
变量)可以停止订阅。
取值
Getters
把状态传进去,返回经过一系列计算或重组的其他状态,保持响应式。类似组件的computed
用于封装计算属性,有缓存的功能,getters
的第一个参数是state
。
Getters 把状态传进去,返回经过一系列计算或重组的其他状态,保持响应式。
传参
调用
1、同一个store
里面直接调用
2、不同的store
,调用其他的getter
更新操作
用于修改数据,有点儿类似 methods
的概念;action
定义的函数可以是普通函数从而可以通过 this
访问整个store
实例,同时该函数可以传入任意参数并返回任何数据。
注意:actions
中的方法,可以通过 this
访问到整个存储实例,所以这个时候就不能使用箭头函数,因为箭头函数内部的this
指向就是外部。
监听action
通过 store.$onAction()
,可以监听action
的动作及结果等:
- name — action 函数的名称
- store — store 实例,这里是 mainStore
- args — action 函数参数数组
- after, — 钩子函数,在action函数执行完成返回或者resolves后执行
- onError– 钩子函数,在action函数报错或者rejects后执行
可以通过调用 mainStore.$onAction
返回的值来手动停止订阅;store.$onAction
默认在所在组件卸载时会被自动删除,可以通过传递第二个参数 true
,来将action
订阅和所在组件分开(即组件卸载时,订阅依然有效)。
Pina插件
pinia store
支持扩展,通过 pinia
插件我们可以实现以下:
- 给
store
添加新属性 - 给
store
添加新选项 - 给
store
添加新方法 - 包装已存在的方法
- 修改甚至删除
actions
1、创建一条静态的属性
2、在所有的store
都可以访问到上面添加的text
属性
3、pinia
插件是一个函数,可以选择返回要添加到store
中的属性,它接收一个可选参数,context
- app : 当前应用
Vue.createApp()
创建的app
- options :
defineStore
配置的数据 - pinia : 当前通过
createPinia()
创建的pinia
实例 - store :当前
store
实例
4、添加一个内部属性
5、添加一个外部属性
当需要添加来自其他库或不需要响应式的数据时,应该用 markRaw()
包装传递的对象。markRaw
来自 vue3
,可以标记一个对象,使其永远不会转换为 proxy
。返回对象本身。
6、pinia-plugin-persistedstate
pinia和vuex都有一个通病,就是数据持久化需要手动修改,插件本身不具备数据持久化的能力,当页面刷新或者应用更新后所有的状态数据均会丢失。
一般来说在vuex中我们的解决发放就是利用缓存去处理,在pinia 中有一个好用的插件可以解决这个问题。
$ yarn add pinia-plugin-persist # 或者npm
$ npm install pinia-plugin-persist