Pinia和Vuex一样都是是vue的全局状态管理器。其实Pinia就是Vuex5,只不过为了尊重原作者的贡献就沿用了这个名字。 vue3.x中建议用pinia
以vue3.x中使用 vuex 和 pinia 来对比总结:
安装
Vuex
npm i vuex -S
Pinia
npm i pinia -S
挂载
Vuex
- 在src目录下 新建 store目录 -> store目录下 新建 index.js文件
import { createStore } from 'vuex'
export default createStore({
//全局state,类似于vue种的data
state() {
return {
vuexmsg: "hello vuex",
name: "xiaoyue",
};
},
//修改state函数
mutations: {
},
//提交的mutation可以包含任意异步操作
actions: {
},
//类似于vue中的计算属性
getters: {
},
//将store分割成模块(module),应用较大时使用
modules: {
}
})
- mian.js中引进注册
import { createApp } from 'vue'
import App from './App.vue'
import store from '@/store'
createApp(App).use(store).mount('#app')
- .vue组件中使用
<template>
<div></div>
</template>
<script setup>
import { useStore } from 'vuex'
let vuexStore = useStore()
console.log(vuexStore.state.vuexmsg); //hello vuex
</script>
Pinia
没有了mutations和modules
- main.js中引入注册
import { createApp } from "vue";
import App from "./App.vue";
import {createPinia} from 'pinia'
const pinia = createPinia()
createApp(App).use(pinia).mount("#app");
- 在src目录下 新建 store目录 -> store目录下 新建storeA.js
import { defineStore } from "pinia";
//1. Option Store
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
// 2. Setup Store: 与 Vue 组合式 API 的 setup 函数 相似,可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象
export const useCounterStore = defineStore("counter", () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubleCount, increment };
});
在 Setup Store 中:
- ref() 就是 state 属性
- computed() 就是 getters
- function() 就是 actions
- 组件中使用
<template>
<div></div>
</template>
<script setup>
import { storeA } from '@/store/storeA'
let piniaStoreA = storeA()
console.log(piniaStoreA.count); //0
</script>
pinia中没有了mutations和modules,pinia不必以嵌套(通过modules引入)的方式引入模块,因为它的每个store便是一个模块,如storeA,storeB... 。在我们使用Vuex的时候每次修改state的值都需要调用mutations里的修改函数(下面会说到),因为Vuex需要追踪数据的变化,这使我们写起来比较繁琐。而pinia则不再需要mutations,同步异步都可在actions进行操作,至于它没有了mutations具体是如何最终到state变化的,这里我们不过多深究,大概好像应该是通过hooks回调的形式解决的把(我也没研究过,瞎猜的。
修改状态
Vuex
import { createStore } from "vuex";
export default createStore({
strict: true,
//全局state,类似于vue种的data
state() {
return {
vuexmsg: "hello vuex",
}
},
//修改state函数
mutations: {
setVuexMsg(state, data) {
state.vuexmsg = data;
},
},
//提交的mutation可以包含任意异步操作
actions: {
async getState({ commit }) {
//const result = await xxxx 假设这里进行了请求并拿到了返回值
commit("setVuexMsg", "hello juejin");
},
}
});
<template>
<div>{{ vuexStore.state.vuexmsg }}</div>
</template>
- 可以直接修改state中的值,但一般不建议这样做,这样vuex就追踪不到数据的变化了
import { useStore } from 'vuex'
let vuexStore = useStore()
vuexStore.state.vuexmsg = 'hello juejin'
console.log(vuexStore.state.vuexmsg)
- 可以通过提交mutation,通过mutation去修改state中值, 建议这样做
import { useStore } from 'vuex'
let vuexStore = useStore()
vuexStore.commit('setVuexMsg', 'hello juejin');
console.log(vuexStore.state.vuexmsg)
- 可以通过dispatch分发action, vuex内action在去提交mutation来修改state
import { useStore } from 'vuex'
let vuexStore = useStore()
vuexStore.dispatch('getState')
一般vuex中actions是放异步函数,拿请求后端接口为例,当后端接口返回值的时候,actions中会提交一个mutations中的函数,然后这个函数对vuex中的状态(state)进行一个修改,组件中再渲染这个状态
Pinia
import { defineStore } from "pinia";
export const storeA = defineStore("storeA", {
state: () => {
return {
piniaMsg: "hello pinia",
name: "xiao yue",
};
},
actions: {
setName(data) {
this.name = data;
},
},
});
- 直接修改,相比于vuex,pinia每次直接修改,调试工具是可以记录到变化的
import { storeA } from '@/store/storeA';
const piniaStoreA = storeA();
console.log(piniaStoreA.piniaMsg); // hello pinia
piniaStoreA.piniaMsg = 'hello juejin';
console.log(piniaStoreA.piniaMsg); // hello juejin
- 通过$patch 去修改
import { storeA } from '@/store/storeA';
const piniaStoreA = storeA();
piniaStoreA.$patch({
piniaMsg: 'hello juejin',
name: 'wxz'
});
// $patch的参数可以是回调函数
piniaStoreA.$patch((state)=>{
state.piniaMsg = 'hello juejin';
state.name = 'wxz';
});
- 通过调用action中方法去修改,直接调用方法而不需要dispatch。 建议用这种处理方法,这样的话,可以实现整个数据流程都在状态管理器内部,便于管理
import { storeA } from '@/store/storeA';
const piniaStoreA = storeA();
piniaStoreA.setName('wxz');
- 重置状态 state
Pinia可以使用$reset将状态重置为初始值
import { storeA } from '@/store/storeA';
const piniaStoreA = storeA();
piniaStoreA.$reset();
Pinia解构(storeToRefs)
当需要使用多个state中值时,使用解构往往是最方便的,但es6传统的解构会使 state中值失去响应式, 所以pinia提供了 storeToRefs api去解决这个问题
import { storeA } from '@/store/storeA';
const piniaStoreA = storeA();
const {piniaMsg, name } = storeToRefs(piniaStoreA);
piniaStoreA.$patch({
name: 'daming'
})
// 页面数据发生变化
getters
Vuex中的getters和Pinia中的getters用法是一致的,都具有缓存作用,用于监听响应式依赖变化从而重新计算返回相应值
项目很大时分模块
vuex -> modules
每个模块都拥有自己state,mutations,actions...。般来说每个module都会新建一个文件,然后再引入总的入口index.js中,将其注册到vuex入口index.js文件的modules里。 而为了避免不同模块有重名,一般采用命名空间 namespaced: true
export const moduleA = {
namespaced: true,
state: () => ({
count: 1,
}),
mutations: {
setCount(state, data) {
state.count = data;
},
},
actions: {
getuser() {
//do something
},
},
}
// store/index.js
import moduleA from './modules/moduleA'
export default createStore({
strict: true,
//全局state,类似于vue种的data
state() {
return {
vuexmsg: "hello vuex",
name: "xiaoyue",
};
},
modules: {
moduleA
},
});
Pinia
Pinia每个状态库本身就是一个模块,项目很大需要多个store时,直接定义多个store传入不同的id即可
import { defineStore } from "pinia";
export const storeA = defineStore("storeA", {...});
export const storeB = defineStore("storeB", {...});
export const storeC = defineStore("storeB", {...});