介绍
Pinia是Vue的一个全新状态管理(Store)库,可以理解为下一个版本的Vuex;也就是Vuex5.0;并且Pinia已经被纳入官方账户下,也就是github/vue.js下,并且Pinia的作者也是Vue的核心维护人员。注意:Pinia只支持Vue;
Pinia 最初是在2019年11月左右使用Composition API重新设计Vue Store。从那时起,最初的原则仍然相同,但Pinia同时适用于Vue 2和Vue 3,并且不要求您使用Composition API;当时的PR设计介绍了他基本的希望支持的功能:
- 对Vue2和Vue3中Options API、Composition API的支持;
- 没有mutations,只有state, getters, actions;
- 不需要modules模块化拆分;
- 对TypeScrip友好的支持;
- 自动化代码拆分;
- 支持Vue DevTools
- 支持服务端渲染,支持插件扩展功能
- 模块热更新:无需重新加载页面即可更改容器,热更新时候保持现有的状态
关于这个名字Pinia(发音为/piːnjʌ/,就像英语中的“peenya”)是最接近piña(西班牙语中的 “菠萝pineapple”)的一个有效的包名。事实上,菠萝是一群单独的花朵结合在一起,形成了多个果实的一种水果。与Stores类似,每个store都是独立生成的,但他们最终都是连接在一起的。菠萝也是一种原产于南美洲的美味热带水果。
Pinia与Vuex对比
Pinia从使用的角度和之前的Vuex几乎是一样的,但是比Vuex更简单了,Pinia的体积更小(性能更好);
一、核心概念
| Vuex | Pinia |
|---|---|
| State | State |
| Getters | Getters |
| Mutations | Actions |
| Actions |
二、版本问题
| Vuex:当前最新版本为4.x | Pinia:当前版本为2.x |
|---|---|
| 1.Vuex4.x用于Vue3 | 1.同时支持Vue2和Vue3 |
| 2.Vuex3.x用于Vue2 | 2.可以认为是Vuex5;并且被官方接管; |
三、不同点
- 没有mutations
- 没有模块的嵌套结构,但是可以使用类似于hooks引入,在store之间交叉组合使用;
- 更好的typecript支持
- 随时受用使用store注册
- 没有命名空间模块,扁平架构,可以认为所有的stores都是命名空间
注意:建议新项目使用Pinia;老项目可迁移;
Pinia使用
一、安装使用
1.引入
yarn add pinia
# or with npm
npm install pinia
2.使用
// main.ts
import { createPinia } from 'pinia'
app.use(createPinia())
// store/useUserStore.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('storeId', {
state: () => {
return {
count: 0,
}
},
getters:{},
actions:{}
})
// 组件中使用
import { useUserStore } from './store/useUserStore'
const store = useUserStore();
// const { count } = storeToRefs(store)
二、使用注意 Vue3中
import { defineStore } from 'pinia'
// 参数1:store的Id,必须是唯一的,将来Pinia会所有的store把挂在到根下
// 参数2:对象
// 返回值是一个函数,调用得到当前的store实例
export const useUserStore = defineStore('storeId', {
/**
*类似于Vue中的data,用来存储状态
* 1.必需是函数:这是为了在服务端渲染避免交叉渲染请求导致的数据状态污染
* 2.箭头函数,为了更好的TS类型推导
*/
state: () => {
return {
storeId: 1234,
userName: '张三',
arr: [1,2,3],
money: 1000
}
},
/**
* 类似于组件中的computed, 用来封装计算属性,有缓存功能
*/
getters:{
// 函数接受一个可选的state
// moneyDouble (state) {
// console.log('moneyDouble')
// return state.money * 2
// }
// 如果在getters中使用了this,必须手动的指定返回值类型
moneyDouble (): number{
console.log('moneyDouble')
return this.money * 2
}
},
/**
* 类似于组件中的methods,封装业务逻辑,修改state
*/
actions:{
changeState(val: string){ // 不能使用箭头函数,this
this.userName = val + this.userName
// this.$patch({})
// this.$pathc(state=>{})
// $reset() 将当前的store初始化
}
},
// 插件:开启数据缓存
persist: {
enabled: true,
strategies: [
{
storage: localStorage,
paths: ['name', 'age']
}
]
}
})
使用方式和Hooks很类似,store之前的调用和在组件内部的调用是一样的;
// 问题1:这样数据不是响应式的
// const {storeId, userName} = store
// 解决:storeRefs, 原因主要是由于Pinia把state做了reactive处理,用refs做响应式代理
const {storeId, userName, moneyDouble} = storeToRefs(store)
console.log(userName.value)
// 问题2:修改数据的方式
const changeName = ()=>{
// 方式一:数据的修改--最简单
store.userName = '李四'
// 方式二:如果需要修改多个数据,建议使用$patch批量更新,内部做了优化
store.$patch({
userName: '李四',
storeId: 5678
})
// 方式三:$patch传入一个函数,更好的批量更新
store.$patch(state=>{
state.userName = '李四'
state.storeId = 5678
state.arr.push(5)
})
// 方式四:如果业务逻辑较为复杂使用action
store.changeState('你好')
}
其他API:
- $subscribe():订阅State
1.和Vuex中的subscribe一样,类似于watch;与watch()相比,使用$subscribe()的优势在于,订阅只会在patches之后触发一次;
2.默认情况下,状态订阅被绑定到添加它们的组件上(如果store在组件的setup()中)。这意味着,当组件被卸载时,它们将被自动删除。如果你想在组件卸载后保留它们,传递{ detached: true } 作为第二个参数来从当前组件中分离状态订阅:
someStore.$subscribe(callback,{detached:true})
- $onAction():订阅action
1.观察actions及其结果。传递给它的回调函数在action本身之前执行。在处理promises之后,允许您在action resolves之后执行函数;链接
2.支持第二个参数: someStore.$onAction(callback,true)
- $dispose(): 注销store
三、插件使用
方式:pinia.use(Plugin)
Pinia持久化存储插件 文档
npm i pinia-plugin-persist --save
使用
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)