了解pinia,它vuex相比有什么不同?

Pinia 与vuex都是vue的全局状态管理器,可以说pinia就是vuex5,接下来本文通过vue3的形式来对比一下这两个全局状态管理器有何不同点。

安装

1
2
3
4
5
// vuex
npm i vuex -S

// pinia
npm i pinia -S

挂载

两个状态管理器都需要在main.js中挂载到vue实例上

vuex的挂载过程

在src下新建store/index.js目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { createStore } from 'vuex'

export default createStore({
state() {
return {
name: 'YoLin'
};
},
mutations: {
},
actions: {
},
getters: {
},
modules: {
}
})
  • state:全局state,类似于vue种的data,用于声明全局的状态变量。
  • mutations:通过commit 触发mutation来修改state,即修改state的函数,可记录追踪数据state变化。
  • actions:用于执行一些异步操作,并提交mutation更新state。
  • getters:可以看作和vue中的计算属性一样的能力。
  • modules: 将store分割成模块,当应用较大时使用。

在main.js上进行挂载

1
2
3
4
import { createApp } from 'vue'
import App from './App.vue'
import store from '@/store'
createApp(App).use(store).mount('#app')

使用:

1
2
3
4
5
<script setup>
import { useStore } from 'vuex'
let store = useStore()
console.log(store.state.name)
</script>

pinia的挂载过程

mian.js中引入

1
2
3
4
5
import { createApp } from "vue"
import App from "./App.vue"
import {createPinia} from 'pinia'
const pinia = createPinia()
createApp(App).use(pinia).mount("#app")

创建store目录,目录一下每一个文件相当于一个模块,无需嵌套(通过modules引入)的方式引入模块。

store/storeA.js

1
2
3
4
5
6
7
8
9
10
11
import { defineStore } from "pinia";

export const storeA = defineStore("storeA", {
state: () => {
return {
name: "YoLin",
};
},
getters: {},
actions: {},
});

使用:

1
2
3
4
5
<script setup>
import { storeA } from '@/store/storeA'
let storeA = storeA()
console.log(storeA.name)
</script>

可以对比看出pinia中没有mutations和mudules,在vuex中修改state需要调用mutations里的函数,才能达到追踪数据变化的目的,而pinia不需要,同步和异步都定义在actions中进行操作。pinia不需要嵌套的方式引入,一个store文件就是一个模块。

修改状态

  • vuex

    非严格模式下,可以直接修改,但这样vuex不能够记录每一次state的变化记录,影响我们的调试

    1
    2
    3
    4
    5
    6
    <script setup>
    import { useStore } from 'vuex'
    let store = useStore()
    vuexStore.state.name = 'hello YoLin'
    console.log(store.state.name)
    </script>

    严格模式下,则必须通过mutations进行修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // store/index.js
    import { createStore } from "vuex";

    export default createStore({
    strict: true,
    state: {
    name: "YoLin",
    },
    mutations: {
    setName(state, data) {
    state.name = data;
    },
    },
    ...
    });

    // App.vue
    <script setup>
    import { useStore } from 'vuex'
    let store = useStore()
    store.commit('setName', 'hello YoLin')
    </script>

    或者在组件中通过dispatch调用actions来提交mutations进而修改state,

    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
    // store/index.js
    import { createStore } from "vuex";

    export default createStore({
    strict: true,
    state: {
    name: "YoLin",
    },
    mutations: {
    setName(state, data) {
    state.name = data;
    }
    },
    actions: {
    changeName({ commit }, value) {
    commit('setName', value)
    }
    }
    ...
    });

    // App.vue
    <script setup>
    import { useStore } from 'vuex'
    let store = useStore()
    store.dispatch('changeName', 'hello YoLin')
    </script>

    在vuex的使用中,actions中一般是先执行异步请求,当获取到后端返回的内容后,通过提交mutation的形式更新数据。

  • pinia

    相比vuex,pinia是可以直接修改状态的。

    1
    2
    3
    4
    5
    <script setup>
    import { storeA } from '@/store/storeA'
    let storeA = storeA()
    storeA.piniaMsg = 'hello YoLin'
    </script>

    也可以通过$patch更新一个或多个数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    storeA.$patch({
    name: 'hello YoLin',
    ...
    })
    // or function
    storeA.$patch((state) => {
    state.name = 'hello YoLin'
    ...
    })

    或者通过actions进行修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { defineStore } from "pinia";
    export const storeA = defineStore("storeA", {
    state: () => {
    return {
    name: "YoLin",
    };
    },
    actions: {
    setName(data) {
    this.name = data
    }
    }
    })

    // App.vue
    import { storeA } from '@/store/storeA'
    let storeA = storeA()
    storeA.setName('YoLinDeng')

    重置state可以通过$reset

    1
    storeA.$reset()

pinia解构

当使用es6的解构赋值对state进行解构的时候,state会失去响应式,这个时候可以使用storeToRefs来避免state失去响应式。

1
2
3
4
import { storeA } from '@/store/storeA'
import { storeToRefs } from 'pinia'
let storeA = storeA()
let { name } = storeToRefs(storeA)

getters

对于getters来说vuex和pinia是一致的,它可以监听对应state的变化,动态计算返回值,getters的值也具有缓存特性,也就是只有在首次和依赖方式改变的时候才会触发getters函数执行。

modules

如果项目比较大的情况,如果只使用单一模块,会显得十分的臃肿难维护,vuex允许将其分割成模块(modules),每个模块单独维护自己的state、getters、mutations、actions,而pinia每个状态库本身就是一个模块。