简洁明了,pinia就像是vuex的新版本。官网的解释:
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。
pinia的优点:
Vue2和Vue3都支持,这让我们同时使用Vue2和Vue3的小伙伴都能很快上手。
pinia中只有state、getter、action,抛弃了Vuex中的Mutation,Vuex中mutation一直都不太受小伙伴们的待见,pinia直接抛弃它了,这无疑减少了我们工作量。
pinia中action支持同步和异步,Vuex不支持
良好的Typescript支持,毕竟我们Vue3都推荐使用TS来编写,这个时候使用pinia就非常合适了
无需再创建各个模块嵌套了,Vuex中如果数据过多,我们通常分模块来进行管理,稍显麻烦,而pinia中每个store都是独立的,互相不影响。
体积非常小,只有1KB左右。
pinia支持插件来扩展自身功能。
支持服务端渲染。
思路分析
store
store简单来说就是数据仓库的意思,我们数据都放在store里面。当然你也可以把它理解为一个公共组件,只不过该公共组件只存放数据,这些数据我们其它所有的组件都能够访问且可以修改。 我们需要使用pinia提供的defineStore()方法来创建一个store,该store用来存放我们需要全局使用的数据。
创建store很简单,调用pinia中的defineStore函数即可,该函数接收两个参数:
name:一个字符串,必传项,该store的唯一id。
options:一个对象,store的配置项,比如配置store内的数据,修改数据的方法等等。
我们可以定义任意数量的store,因为我们其实一个store就是一个函数,这也是pinia的好处之一,让我们的代码扁平化了,这和Vue3的实现思想是一样的。使用store很简单,直接引入我们声明的useUsersStore 方法即可。
state
前面我们利用defineStore函数创建了一个store,该函数第二个参数是一个options配置项,我们需要存放的数据就放在options对象中的state属性内。在数据的读取上非常简单,我们只需要解构出即可使用,包括模版中。
import { useUsersStore } from "../src/store/user";
import { storeToRefs } from "pinia";
const store = useUsersStore();
const { name, age, sex } = store;
无论任何层级组件都可以轻松使用。修改时我们需要通过利用pinia的storeToRefs函数,将state中的数据变为了响应式。
const { name, age, sex } = storeToRefs( store);
重置时直接使用 直接调用store的reset()方法即可。当我们想要批量修改多个属性时,pinia提供的patch方法。
getter
大家可以把getter想象成Vue中的计算属性,它的作用就是返回一个新的结果,就是处理state数据。使用时我们可以直接store.方法,具体可以参考下面的例子。 但是有时候我们需要在这一个getter方法中调用其它getter方法,这个时候如何调用呢? 其实很简单,我们可以直接在getter方法中调用this,this指向的便是store实例,所以理所当然的能够调用到其它getter。当然getter也可以接受我们传入参数进行计算操作。这些也同样可以参考下面的例子。
actions
actions属性值同样是一个对象,该对象里面也是存储的各种各样的方法,包括同步方法和异步方法。在需要用到的地方直接调用store中的actions方法即可。
与vuex比较
先来看官网描述:
Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分内容,并决定实现它 取而代之的是新的建议。
与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。
当我们通过vuex修改state时 , vuex中的流程是首先actions一般放异步函数,拿请求后端接口为例,当后端接口返回值的时候,actions中会提交一个mutations中的函数,然后这个函数对vuex中的状态(state)进行一个修改,组件中再渲染这个状态。
而当我们通过vuex修改state时,是直接修改的。
如果项目比较大,使用单一状态库,项目的状态库就会集中到一个大对象上,显得十分臃肿难以维护。所以Vuex就允许我们将其分割成模块(modules),每个模块都拥有自己state,mutations,actions...。而Pinia每个状态库本身就是一个模块。Pinia没有modules,如果想使用多个store,直接定义多个store传入不同的id即可。
demo
我用vue3+TS+pinia写了一个demo,大家可以本地跑起来。废话不多说,直接上代码,记得配置好vue3和ts。
在App.vue中(src\App.vue)
< template >
< img alt= "Vue logo" src= "./assets/logo.png" />
< p >姓名: {{ name }}</ p >
< p >年龄: {{ age }}</ p >
< p >性别: {{ sex }}</ p >
< p >新年龄: {{ store. getAddAge( 1100) }}</ p >
< p >调用其它getter: {{ store. getNameAndAge }}</ p >
< button @ click=" changeName" >直接修改store更改姓名 </ button >
< button @ click=" reset" >调用reset重置store数据 </ button >
< button @ click=" patchStore" >调用patch批量修改数据 </ button >
< button @ click=" saveName" >调用aciton更改姓名 </ button >
<!-- 子组件 -->
< Child ></ Child >
</ template >
< script setup lang= "ts" >
import Child from "./Child.vue";
import { useUsersStore } from "../src/store/user";
import { storeToRefs } from "pinia";
const store = useUsersStore();
const { name, age, sex } = storeToRefs( store);
const changeName = () => {
store. name = "张三";
console. log( store);
};
// 重置store
const reset = () => {
store. $reset();
};
// 批量修改数据
const patchStore = () => {
store. $patch({
name : "张三",
age : 100,
sex : "女",
});
};
// 调用actions方法
const saveName = () => {
store. saveName( "我是小猪");
};
</ script >
在Child.vue中( src\Child.vue )
< template >
< h1 >我是child组件 </ h1 >
< p >姓名: {{ name }}</ p >
< p >年龄: {{ age }}</ p >
< p >性别: {{ sex }}</ p >
< button @ click=" changeName" >更改姓名 </ button >
</ template >
< script setup lang= "ts" >
import { useUsersStore } from "./store/user";
import { storeToRefs } from 'pinia';
const store = useUsersStore();
const { name, age, sex } = storeToRefs( store);
const changeName = () => {
store. name = "小猪";
};
</ script >
在main.ts中(src\main.ts)
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia";
const pinia = createPinia();
const app = createApp( App);
app. use( pinia);
app. mount( "#app");
在user.ts中(src\store\user.ts)
import { defineStore } from "pinia";
// 第一个参数是应用程序中 store 的唯一 id
export const useUsersStore = defineStore( "users", {
state : () => {
return {
name : "我我我",
age : 22,
sex : "男",
};
},
getters : {
getAddAge : ( state) => {
return ( num: number) => state. age + num;
},
getNameAndAge() : string {
return this. name + this. getAddAge( 0); // 调用其它getter
}
},
actions : {
saveName( name: string) {
this. name = name;
},
},
});
该demo涵盖内容:
创建store,使用store。
创建state,使用state,添加state,读取state数据,修改state数据,重置state数据,批量修改state数据。
添加getter,使用getter,getter中调用其他getter,getter传参。
添加actions,使用actions。
总结
pinia大家学习起来也会感觉很轻松,没有vuex繁重。定义store,使用数据,修改数据,使用方法都变得非常轻松。大家都说,小项目拿pinia管理,大项目用vuex,可能工作开发中使用不到,但是可以学习它的思想。