浅析pina与vuex的区别
2024-12-09 11:13:16

无论是vuex还是pina,本质上都是为了解决项目中的全局数据存储的问题,没有什么更优或者更劣的说法。

不过,vuex主要是应用在vue2的项目,pina则是随着Vue3升级产生的社区产物。

pina由原vuex团队,为了配合vue3的升级,特意写的新工具,所以二者在使用上会有一定相似性。

正文

在正式开始写这篇文档之前,稍微科普一下,vuexpina都是一个团队开发的,所以这二者在使用上会有不少类似的地方。

随着vue3的推广,pina也逐渐开始在社区中推广,成了vue3的开源项目新宠儿。

早期也有很多开发者在vue2的项目中用pina,或在vue3的项目中用vuex。

不过,随着时间推移,vue2中使用vuex,vue3中pina,这成了社区约定的常规习惯,大多vue开源项目你都能看到他们这么用。

如果要问为什么,只是社区逐渐应用产生的习惯罢了,并没有什么特殊的讲究。

vuex

Vuex设计为一个全局状态管理的单例模式,有一个中心化的存储来管理应用的所有状态。

它基于Vue 2的Options API,强调状态的集中管理和严格的规则,包括State、Getters、Mutations(用于同步更改状态)和Actions(可以处理异步逻辑)。

其使用与pinia的CompositionAPI 的写法还是略有不同的。

action和mutation的区别

很多人早期在使用vuex的时候,可能有些分不清actionmutation的区别。

所以,在正式介绍vuex之前,我们先在简单介绍一下二者的区别。

  • mutation更专注于修改state,必须是同步执行(无法在mutation中使用异步方法)。
  • action提交的是mutation,而不是直接更新数据,可以是异步的,如业务代码,异步请求。
  • action可以包含多个mutation

main.js文件

1
2
3
4
5
6
7
8
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import store from './store' // vuex是导入状态仓库,pinia是创建实例对象createPinia

const app=createApp(App)
app.use(store)
app.mount('#app')

store文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { createStore } from 'vuex'
const state = {
counter: 0,//计数状态
user: null
}
const actions = {
//修改状态的方法
increment: ({ commit }) => {
// commit 提交一项修改 提交给mutations
commit('increment')
},
}
//所有的状态修改都要经过mutations,只有mutations 可以修改状态
const mutations = {
increment(state) {
state.counter++
}
}
//getter
const getters = {
doubleCount: (state) => {
return state.counter * 2
}
}
//除了读操作,对写操作十分严格
const store = createStore({state,actions,mutations,getters}) //创建实例对象
export default store

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<h2>App.vue:</h2>
<div>
count: {{ store.state.counter }}
</div>
<button @click="increment">+</button>
<div>
doubleCount: {{store.getters.doubleCount}}
</div>
<AppHeader />
</template>

<script setup>
import {useStore} from 'vuex'
import AppHeader from './components/app-header.vue'
const store=useStore()
const increment = () => {
//使用dispatch派出increment action的方法
store.dispatch('increment')
}
</script>

pinia

Pinia针对Vue 3设计,充分利用Composition API,提倡更简洁和直观的状态管理方式。

每个store在Pinia中都是独立的,同时为了兼容Vuex的写法Pinia仍然支持使用选项式API,也是现在主流的状态管理库。

main.js文件

1
2
3
4
5
6
7
8
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'

const pinia=createPinia() //创建pinia实例对象
createApp(App)
.use(pinia) // use这个实例对象
.mount('#app')

store文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { defineStore } from "pinia";
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter',
() => {
// state
const count = ref(0);
// actions
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
const reset = () => {
count.value = 0;
};
const doubleCount = computed(() => {
return count.value * 2;
});
return { count, increment, decrement, reset, doubleCount };
},
);
export const useStore = defineStore('store',
() => {
const someState=ref('hello Pinia');
const incrementSomeState = () => {
someState.value += '!'
}
return { someState , incrementSomeState }
},
);

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<h1>App</h1>
<h1>Counter: {{ store.count }}</h1>
<h1>Double:{{ store.doubleCount }}</h1>
<button @click="store.increment">Increment</button>
<button @click="store.decrement">decrement</button>
<button @click="store.reset">reset</button>
</div>
<h1>String: {{ hel.someState }}</h1>
<button @click="hel.incrementSomeState">+ ! </button>
<Child />
</template>
<script setup>
import {useCounterStore,useStore} from '@/Pinia/counter.js' //引入定义好的状态库
import Child from '@/components/child.vue'
const store=useCounterStore()
const hel=useStore()
</script>

二者区别

  1. 相对于vuex,pina是用tyepscript完成的,所以,代码提示效果更好。
  2. main.js文件中,vuex使用的是导出的store仓库,而pinia是使用实例化对象。
  3. pina弃用了mutation,如果想要完成数据修改,可以直接用action操作就可以了。
  4. pina中不再使用modules,而是直接声明的对应的对象调用即可。

modules

如果项目比较大,使用单一状态库,项目的状态库就会集中到一个大对象上,显得十分臃肿难以维护。

所以Vuex就允许我们将其分割成模块(modules),每个模块都拥有自己state,mutations,action等。

pina

而Pinia每个状态库本身就是一个模块,pinia没有modules,如果想使用多个store,直接定义多个store传入不同的id即可。

1
2
3
4
5
import { defineStore } from "pinia";

export const storeA = defineStore("storeA", {...});
export const storeB = defineStore("storeB", {...});
export const storeC = defineStore("storeB", {...});

Vuex

一般来说每个module都会新建一个文件,然后再引入这个总的入口index.js中,这里为了方便就写在了一起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { createStore } from "vuex";
const moduleA = {
state: () => ({
count:1
}),
mutations: {
setCount(state, data) {
state.count = data;
},
},
actions: {
getuser() {
//do something
},
},
getters: { ... }
}

const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}

export default createStore({
strict: true,
//全局state,类似于vue种的data
state() {
return {
vuexmsg: "hello vuex",
name: "xiaoyue",
};
},
modules: {
moduleA,
moduleB
},
});

使用moduleA

1
2
3
4
5
6
import { useStore } from 'vuex'
let vuexStore = useStore()
console.log(vuexStore.state.moduleA.count) //1
vuexStore.commit('setCount', 2)
console.log(vuexStore.state.moduleA.count) //2
vuexStore.dispatch('getuser')

一般我们为了防止提交一些mutation或者actions中的方法重名,modules一般会采用命名空间的方式 namespaced: true 如moduleA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const moduleA = {
namespaced: true,
state: () => ({
count: 1,
}),
mutations: {
setCount(state, data) {
state.count = data;
},
},
actions: {
getuser() {
//do something
},
},
}

此时如果我们再调用setCount或者getuser

1
2
vuexStore.commit('moduleA/setCount', 2)
vuexStore.dispatch('moduleA/getuser')
  1. store仓库中的actions是提交修改方法名,而真正修改是通过mutationsactions就像是秘书,而mutation像是boss,你不能直接找到boss修改属性,而必须通过dispatch派出increment action的方法,让mutation去修改这个值。
  2. vuex中的getter是不需要引入computed这个方法的,他会自动一直监听内部的状态是否发生改变。

结语

pina和vuex的区别,算是vue3的常规面试题之一,我之前虽然大致整理过,但是没有系统性的梳理。

如今借着别人的文档仔细梳理了一遍,心里对二者的使用心得也是更上一层楼。

不过,随着vue3的逐渐推广,未来pina一定会在社区中提高占用比。

如果要是手里有新项目的朋友,最好还是在项目中使用pina,这也是对社区不断发展的一种适应。

参考

简介 | Pinia (vuejs.org)

开始 | Vuex (vuejs.org)

vue3通信大全(三)—— 全局状态管理库pinia,vuex