特点:
- Vue2 和 Vue3 都能支持;
- 抛弃传统的 `Mutation` ,只有 `state, getter` 和 `action(同步异步都支持)` ,简化状态管理库;
- 不需要嵌套模块,符合 Vue3 的 Composition api,让代码扁平化;
- TypeScript支持;
- 代码简洁,透明、自动化的代码分割。
一、和vuex的区别
- pinia只有 `state, getter` 和 `action(同步异步都支持)`;vuex的同步在`mutation`中完成,`action`处理异步;
- pinia没有总出口,全是模块化,需要定义模块名称,当多个模块需要协作的时候,需要引入多个模块;vuex是有总出口的,当使用模块化的时候不需要引入多个模块;
- pinia在修改数据的时候不需要通过其他api;vuex需要通过`commit`、`dispatch`。
二、基本使用
1.创建store
import { defineStore } from 'pinia';
export const mainStore = defineStore('main',{
state:() => {
return {
msg:'Hello world!'
}
},
getters:{},
actions:{}
})
2.使用store
<script setup lang="ts">
import { mainStore } from '../store/index';
const store = mainStore();
</script>
<template>
<h2>{{ store.msg }}</h2>
</template>
3.解构store
当store中的多个参数需要被使用到的时候,更简洁的写法,通常采用解构的方式一次性获取所有的变量名。
注意:ES传统方式解构(能获取到值,但是不具有响应性),如下:
<script setup lang="ts">
import { mainStore } from '../store/index';
const store = mainStore();
const { msg } = store; // 这种写法,msg不会响应式更新。。。
</script>
<template>
<h2>{{ msg }}</h2>
</template>
Pinia解构方法:storeToRefs,如下:
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { mainStore } from '../store/index';
const store = mainStore();
const { msg } = storeToRefs(store);
</script>
<template>
<h2>{{ msg }}</h2>
</template>
三、修改数据状态
1.简单修改
直接在方法中通过 `store.属性名` 修改;
<script setup lang="ts">
import { mainStore } from '../store/index';
const store = mainStore();
const addOne = () =>{
store.count++;
}
</script>
<template>
<button @click="addOne">+1</button>
</template>
2.多条数据修改
当修改多条数据时,pinia官方推荐使用 $patch ;该方法是经过优化的,会加快修改速度,对性能有很大好处。
$patch方法可以接收两种类型的参数:函数和对象。
1)$patch + 对象;
2)$patch + 函数;
<script setup lang="ts">
import { mainStore } from '../store/index';
const store = mainStore();
// $patch + 对象
const onObjClick = () =>{
store.$patch({
msg: store.msg == 'Hello World' ? '111' : '222';
count: store.count++;
})
};
// $patch + 函数
const onFuncClick = () =>{
store.$patch((state)=>{
state.msg = store.msg == 'Hello World' ? '111' : '222';
state.count = store.count++;
})
}
</script>
<template>
<button @click="onObjClick">click1</button>
<button @click="onFuncClick">click2</button>
</template>
3.通过action修改
在store.actions中添加修改数据的方法,在组件中通过 `store.方法名` 调用:
import { defineStore } from 'pinia';
export const mainStore = defineStore('main',{
state:()=>{
return{
msg:'Hello world!',
count:0
}
},
getters:{},
actions:{
changeState(val){
this.count = val;
this.msg = "疫情快过去吧!"
}
}
})
<script setup lang="ts">
import { mainStore } from '../store/index';
const store = mainStore();
const onClick = () =>{
store.changeState(2);
};
</script>
<template>
<button @click="onClick">修改store中的状态</button>
</template>
四、getters
pinia中的getter和vue中的计算属性几乎一样,在获取State值之前做一些逻辑处理。
getter中的值有缓存特性,如果值没有变,多次使用也只会调用一次:
import { defineStore } from 'pinia';
export const mainStore = defineStore('main',{
state:()=>{
return{
msg:'Hello world!'
}
},
getters:{
getCountBuff(state){
console.log('getter被调用');
return `${state.msg}***${state.msg}`;
}
}
})
<script setup lang="ts">
import { mainStore } from '../store/index';
const store = mainStore();
</script>
<template>
<div>
<h2>Getter 获取数据</h2>
<div>{{ store.getCountBuff }}</div>
<div>{{ store.getCountBuff }}</div>
<div>{{ store.getCountBuff }}</div>
<div>{{ store.getCountBuff }}</div>
</div>
</template>
getter不仅可以通过传递 `state` 来获取到数据,还可以直接通过 `this` 来取到数据:
getters:{
getMsgWithThis(): string{
return `${this.msg}***${this.msg}`;
}
}
五、store之间的相互调用
在Pinia中,可以在一个 store1 中引入另一个 store2 ,然后通过调用 store2 的方法,获取到 store2 的状态。
// src/store/store2.js
import { defineStore } from 'pinia';
export const store2 = defineStore('movie',{
state:()=>{
return{
movieList:['泰坦尼克号','绿皮书','肖申克的救赎','阿甘正传','星际穿越']
}
}
})
// src/store/store1.js
import { defineStore } from 'pinia';
import { store2 } from './store2';
export const store1 = defineStore('main',{
state:()=>{
return{
msg:'Hello world!'
}
},
getters:{
getStore2():string[]{
return store2().movieList
}
}
})
六、开启持久化 persist
persist:{
enabled:true,
strategies:[]
}
七、vuex和pinia的优缺点
1.pinia优点:
- 允许你在不重新加载页面的情况下修改store;
- 为typescript设计的,提供了强类型支持,可以在开发中捕获更多的错误,提高代码的可维护性;
- pinia提供devtool支持,有助于增强开发人员使用该工具的体验;
- 摒弃了vuex中的mutation;
- 无需再创建各个模块嵌套了,vuex中如果数据过多通常会分模块进行管理,而pinia中每个store都是独立的,互相不影响;
- 体积非常小,只有1kb左右;
- 支持插件来扩展自身功能;
- 支持服务端渲染;
- 兼容vue2和vue3;
2.pinia缺点:
- 与vuex相比,它没有庞大的社区支持和解决方案;
- 不支持调试功能,如时间旅行和编辑;
3.vuex优点:
-
与pinia相比,它有庞大的社区支持和解决方案;
-
支持调试功能,如时间旅行和编辑;
4.vuex缺点:
-
它对typescript不友好;
-
体积庞大,只适合大型SPA;
八、补充:时间旅行
在前端中,Vuex 借鉴 Flux 单向数据流思想,采用集中式统一管理保存状态。但是这些状态不会随时间改变而变化。为了使状态,可能被捕获、重播或重现,通过时间来回旅行。尤大开发了 vue-devtools 这样的工具,可以帮助我们的 Vue 应用可以实现这种时间旅行!
保证时间旅行的前提:
- 单一的状态树`store`;
- 只能通过`mutation`更改状态;
time travel:
在vue-devtools的vuex状态面板中,有一个神奇的功能:`time travel`,
原理:
所有的状态变更只能通过mutation,并且每次状态的改变都会产生一个全新的state对象,把每次变更的state对象事件都记录下来,展现出一个mutation列表,当你想展现什么时间段的状态,只需要切换到那个时间段的state对象。
每次产生新state的时候,需要对原state对象进行深拷贝,保证每次状态变更时原state不变,操作新的state。
九、总结
总得来说,Pinia 就是 Vuex 的替代版,可以更好的兼容 Vue2,Vue3以及TypeScript。在Vuex的基础上去掉了 Mutation,只保留了 state, getter和action。Pinia拥有更简洁的语法, 扁平化的代码编排,符合Vue3 的 Composition api。