pinia是什么:
pinia是一个跟vuex类似的vue状态管理工具库,尤大在将vue3替换vue默认版本后,强推的就是pinia作为vue新版的状态管理工具。并且pinia的开发团队和vuex是同一个团队。
pinia相较于vuex的优势:
-同时支持vue2和vue3,老项目也可以使用pinia。 -对TS完全支持。-体积较轻,仅有1kb。 -采用模块化设计,符合vue3的Composition api。非常便于拆分状态。 -抛弃了Mutations的操作,只有state、getters和actions.极大的简化了状态管理库的使用。
安装pinia
pnpm i pinia
npm install pinia
创建并挂载pinia实例
1:在main.ts里引入Pinia
import { createPinia } from 'pinia'
2创建pinia实例
const pinia = createPinia()
3挂载到vue的根实例上
app.use(pinia)
创建Store
import { defineStore } from 'pinia';
export const mianStore = defineStore('main', {
state: ()=>{
return {
value: 0
}
},
getters: {},
actions: {}
})
defineStore参数说明: defineStore()方法接收两个参数,第一个参数是id,相当于容器的名字,唯一标识,因为伴随着项目越来越大的问题,会有很多个仓库,所以为了便于管理给每个仓库使用id来区别。 defineStore()方法第二个参数是一个配置对象,里面存放的是store容器的配置, state属性用来存放全局的状态。 getters属性用来监视计算状态的变化,具有缓存的功能。 actions属性用来修改全局的state状态数据。
使用store
//引入store
import { mainStore } from '@/store/index';
const store = mainStore()
//在模板中直接使用
{{store.value}}
使用getters
getters提供的功能类似于vue的计算属性,同时也具有缓存作用。可以将store中的数据再次加工并在外部组件使用。同时可以使用this直接指向store中的数据
getters: {
doubleClick() {
return this.value *2
}
}
//在模板中使用
{{ store.doubleClick }}
使用actions
在Pinia中舍弃了mutations的提交操作,这样我们所有的同步异步操作都可以在actions中处理。promise、请求接口等操作可以在这里书写。
actions: {
//模拟同步操作
addOne() {
this.value++
},
//模拟异步操作
getUserInfo() {
return new Promise((resolve, reject) => {
postMethod(url).then(res => {
if (res.code === 200) {
resolve(res)
const { data } = res.apiData
//继续调用其他的异步方法处理数据
setUserInfo(data)
}
}).catch(.........)
})
},
setUserInfo(data) {
.......to do
}
}
//在外部使用
<button @click="store.getUserInfo">
//在script中使用
store.getUserInfo()
解构数据保持响应式
如果我们使用es6解构的方式试图从store中直接引入数据,抱歉这种行为取到的数据将失去响应式,那么Pinia官方为我们提供了方法使得解构出来的数据依旧能够保持响应式。storeToRefs
//在需要使用的地方引入storeToRefs
import { storeToRefs } from 'pinia';
import { mainStore } from '@/store/index';
const store = mainStore()
//使用storeToRefs包裹要解构的store,即可保证取出的数据依旧保持响应式
const { value } = storeToRefs(store)
修改数据的方法
pinia修改数据的方法大致可以分为三类
- 直接修改
- $patch修改
- 调用actions修改(推荐的方式)
1:直接修改顾名思义,就是直接store.value = 2,这种方式是不推荐的,随意修改数据,会导致debug的成本增加。
2:$patch为我们提供了两种修改数据的方式
第一种批量修改,以对象的形式修改
store.$patch({
value: 3,
count: 5,
arr: [1,2,3]
})
第二种修改某个具体的值,以箭头函数的形式修改
store.$patch(state => {
state.value = 6,
state.count: 8
})
3:通过actions修改数据
//actions中
changeStateData(data) {
this.value = data
}
//组件中
changeData() {
store.changeStateData(89)
}
重置store的数据
const userStore = useUserStore()
userStore.$reset()
Pinia模块化
官方似乎没有强制我们使用module来拆分Pinia来达到模块化目的,即使这样我们仍然要从项目长期维护、多人开发、易于维护的角度考虑。因为项目往后越来越大,维护的数据越来越多,单个store可能会出现数据混乱、多个人写了类似的方法只为达到某个需求。同时vite配合pinia打包时,不会将所有代码都打包进去,他会只打包我们组件使用到的数据,减少体积,所以拆分后面也是有好处的。
那么对Pinia做出模块化的拆分。个人模块化的标准就是一个页面模块独立使用一个store,然后将所有的模块导入到根store上,优雅了哈。
这里我们新建home模块和user模块最后注入到index根store里面

注意导出时的命名和store的唯一id


然后在index注入模块,别名映射一下使用更方便

最后在组件中使用

- 注意点这里结构出来的指如果在script里使用的话需要加
.value,因为其变成了响应式的必然被proxy劫持了,可以理解为该数据被套了一层ref()
多个store相互调用
用法跟上面一样,在需要调用的store引入被调用的store,一般常用于actions里,被调用的store可以直接访问。而调用的store也可以直接修改数据。
//引入需要调用的store
import useUserInfo from "./user";
const userStore = useUserInfo()
//使用state数据
userStore.value
//使用actions方法
userStore.setInfo()
pinia的执行时机及作用域
当我们在某些文件例如JS文件内使用pinia,在引入成功后立即全局声明
const userStore = useUserStore()
这时候会报错,这是因为pinia的执行时机太快导致的。 我们只需要在函数要用到的地方局部声明并使用即可。
数据持久化
vue运行时的数据是存在内存中的,而我们刷新页面之后vue的状态数据会被重置。为了解决这个问题就需要使他的状态管理能够持久化。
//安装插件 pnpm yarn npm都可以。
npm install pinia-plugin-persist --save
//在main.ts使用
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
- key:这里的key请对应上创建store时的第一个参数,store的ID。
- storage:指定store的数据存储在客户端的哪里,local或session里。
- paths:指定store中哪些数据需要被持久化。即state中return对象的键值对的key。
当然,一个store里面的数据可以同时开启在local和session存储。

数据持久化开启后,页面刷新在vue-devTools查看pinia的数据还在。
TODO
毕竟local和session还是有存储大小的限制的。那么还有一种存储方式可以在客户端进行,localforage可以看做一个存在于客户端的数据库,没有大小限制。且读或取无需像local和session那要需要JSON.parse转换数据类型。