Pinia 是 Vue 官方团队成员专门开发的一个全新状态管理库,并且 Vue 的官方状态管理库已经更改为了 Pinia。 在 Vuex 官方仓库中也介绍说可以把 Pinia 当成是不同名称的 Vuex 5,这也意味不会再出 5 版本了。
优点
-
更加轻量级,压缩后提交只有1.6kb。
-
完整的 TS 的支持,Pinia 源码完全由 TS 编码完成。
Pinia 在与 TS 一起使用时,具有可靠的类型判断支持;Vuex 之前对 TS 的支持很不友好。
- 移除 mutations,只剩下 state 、 actions 、 getters,在store内部直接使用this使用state里的数据。
一旦 store 被实例化,就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性;而在使用 Vuex 的时候,更改状态需要纠结选取 mutation 还是 action。
-
不再有 Vuex 里多个 modules 的嵌套结构,可以定义多个 store 并灵活使用。
-
不会再有module的命名空间的概念,不需要记住他们的复杂关系。
-
支持服务端渲染(SSR)。
-
更友好的代码分割机制。
-
提供了 Pinia 状态持久化。配置 | Pinia Plugin Persistedstate
举例说明
针对第4点
Pinia版本:假设我们有一个购物车应用,需要管理用户信息和购物车商品信息,可以用两个 Store 来实现。
javascript
// userStore.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
age: 0,
}),
actions: {
updateName(newName) {
this.name = newName;
},
},
});
// cartStore.js
import { defineStore } from 'pinia';
export const useCartStore = defineStore('cart', {
state: () => ({
items: [],
}),
actions: {
addItem(item) {
this.items.push(item);
},
},
});
Vuex版本:在组件中,通过 this.$store
来访问状态,需要通过命名空间来区分模块,例如 this.$store.state.user.name
或 this.$store.commit('cart/addItem', item)
。
javascript
// store.js
import { createStore } from 'vuex';
export default createStore({
modules: {
// 用户
user: {
state: {
name: '',
age: 0,
},
mutations: {
updateName(state, newName) {
state.name = newName;
},
},
},
// 购物车
cart: {
state: {
items: [],
},
mutations: {
addItem(state, item) {
state.items.push(item);
},
},
},
},
});
针对第5点
Vuex 中,如果没有命名空间,多个模块有相同名称的方法,如模块A和模块B都有updateName
,使用起来会冲突,因为 Vuex 不知道要调用哪个模块的 updateName
。
javascript
// 模块 A
mutations: {
updateName(state, newName) {
state.name = newName;
},
}
// 模块 B
mutations: {
updateName(state, newName) {
state.name = newName;
},
}
通过命名空间namespaced: true,可以将每个模块的作用域限制在模块内部,避免冲突。
javascript
// 模块 A
namespaced: true,
mutations: {
updateName(state, newName) {
state.name = newName;
},
}
// 模块 B
namespaced: true,
mutations: {
updateName(state, newName) {
state.name = newName;
},
}
// 组件中使用
this.$store.commit('moduleA/updateName', 'John');
this.$store.commit('moduleB/updateName', 'Jane');
当然,在 pinia 中没有模块化的概念了,就更不存在需要使用命名空间了。