likes
comments
collection
share

Vuex vs Pinia:深入解析Vue状态管理工具的用法与差异

作者站长头像
站长
· 阅读数 25

随着Vue.js生态系统的不断成熟,开发者们在构建大型应用程序时,越来越倾向于使用状态管理工具来处理组件间的状态共享和业务逻辑的复杂性。在Vue社区中,Vuex 和 Pinia 是两个备受关注的状态管理解决方案。前段时间写过了有关Vuex的文章,今天我将在案例中同时使用两者来展现各自的用法和优势。

安装和使用

通过npm安装Vuex和Pinia:

npm i Vuex
npm i Pinia

引入全局

import store from'./store'//状态仓库
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const Pinia=createPinia()
const app = createApp(App)
app
    .use(store)
    .use(Pinia)
    .mount('#app')

从引入中就可以发现两者的引入方式就存在差异。

  • Vuex:Vuex 的设计基于集中式状态管理的概念,所有组件都共享同一个 store 实例,因此需要在 main.js 中全局注册这个 store。
  • Pinia:Pinia 的设计更侧重于组件内部的状态管理,它允许你创建多个 store 并在需要的地方使用。虽然在 main.js 中也需要注册 Pinia,但这更多是为了整合 Pinia 到 Vue 应用中,而不是为了提供全局的 store 实例。Pinia 的 store 实例通常是通过组合式 API 在组件内部定义和使用的。

创建仓库

我分别创建了Vuex和Pinia管理仓库用于管理购买商品的基本信息和身份信息。从创建中就更加明显的体现了二者的管理方式不同,一个是集中管理,一个是分开的模块化管理。其中的结构也不同,Vuex中包含State、Getter、Mutation、Action、Modules,而Pinia中缺少了Mutation和Modules(一会将在数据的改变中解释其中的不同)。

Pinia有两写法:选项式和组合式(本文我采用的是选项式)。具体可以查看官方文档

Vuex vs Pinia:深入解析Vue状态管理工具的用法与差异

Vuex仓库代码

import { createStore } from "vuex";//只有一个store

//全局状态
//不再有父兄子 陌生人 login
//状态对象
const state={
    count:0,//计数状态
    user:'张三',
    price:20

}

const getters={
    //计算属性 不会修改状态
    allPrice:state=>{
        return state.price*state.count;
    }
}

const actions={
    increment:({commit})=>{

        //commit 提交一项修改 提交给mutations
        commit('increment')
    },
    decrement:({commit})=>{
        commit('decrement')
    }
}
//所有的状态修改都要经过mutations
//只有mutations可以修改状态
const mutations={
    increment(state){
        state.count++;
    },
    decrement(state){
        state.count--;
    }
}
//除了读操作,对写操作非常严格
const store=createStore({
    state,
    getters,
    actions,
    mutations
})

export default store;

Pinia的ageStore代码

import { defineStore } from "pinia";

export const useAgeStore=defineStore('age',{
    state:()=>{
        return {
            year:2002
        }
    },
    getters: {
        age: (state) => {
            return new Date().getFullYear() - state.year;
        }
    }
    ,actions: {
        increment() {
            this.year++;
        },
        decrement() {
            this.year--;
        }
    }
})

Pinia的nameStore代码

import { defineStore } from "pinia";

export const useNameStore=defineStore("name", {
    state: () => ({
        name: "李四"
    }),
    actions: {
        setName(name) {
            this.name = name;
        }
    }
});

数据的获取

先给出html部分代码

<template>
  使用vuex
  <div class="vuex">
    用户名:{{ user }}<br>
    单价:{{ price }}元/个<br>
    数量:{{ count }}个
    <button @click="increment">+</button>
    <button @click="decrement">-</button><br>
    总价:{{ getter }}元
  </div>
  使用pinia
  <div class="pinia">
    <p>姓名:{{ nameStore.name }}</p>
    <p>年龄:{{ ageStore.age }}岁</p>
    <div class="age">
      <p>出生年份:{{ ageStore.year }}年</p>
      <button @click="increment1">+</button>
      <button @click="decrement1">-</button><br>
    </div>
    <div>
      修改姓名:<input type="text" v-model="newname">
      <button @click="submit(newname)">提交</button>
    </div>
  </div>
</template>

Vuex获取数据

Vuex获取数据需要创建使用仓库的api实例,然后通过computed属性获取。

import { useStore } from 'vuex';
import { computed } from 'vue';

const store = useStore();//hooks编程
const count = computed(() => store.state.count);
const user = computed(() => store.state.user);
const price = computed(() => store.state.price);
const getter=computed(()=>store.getters.allPrice)

Pinia获取数据

Pinia获取数据时,只需要引入相应仓库,创建对应实例,然后通过类似nameStore.nameageStore.age的方式使用。相对于Vuex更为便捷。

import { useAgeStore } from './store/ageStore';
import { useNameStore } from './store/nameStore';
const ageStore = useAgeStore();
const nameStore = useNameStore();

数据改变

Vuex的数据更新

当Vuex需要更新状态(这里通过点击事件来实现数据更新)时,通过dispatch调用actions,由actions内部的commit决定何时提交mutation来修改状态。

const increment = () => {
  //派出 increment 函数
  store.dispatch('increment');
}
const decrement = () => {
  //派出 decrement 函数
  store.dispatch('decrement');
}

Pinia的数据更新

当Pinia需要更新时,可以直接调用action中的方法。

const submit = (name) => {
  //派出 submit 函数
  nameStore.setName(name);
}
const decrement1 = () => {
  //派出 decrement 函数
  ageStore.decrement();
}
const increment1 = () => {
  //派出 increment 函数
  ageStore.increment();
}

模块化

  • vuex的modules

在使用vuex时,由于是单一状态数应用的所有的状态会集中在一个store对象中,项目体积过大时就会显得很臃肿,所以vuex也有属于自己的模块化。我们可以看看vuex官方文档

Vuex vs Pinia:深入解析Vue状态管理工具的用法与差异

  • pinia的模块化

pinia的模块化简单来说就是支持创建多store仓库管理。

Vuex与Pinia的主要区别

Vuex vs Pinia:深入解析Vue状态管理工具的用法与差异

Vuex vs Pinia:深入解析Vue状态管理工具的用法与差异

两者的区别在pinia的官方文档上也有一些介绍。总结一下:

  1. 语法糖与灵活性

    • Pinia的语法更接近Vue 3的组合式API,使得状态管理更加直观和简洁。
    • Vuex的语法较为繁琐,尤其是在使用模块时。
  2. 性能优化

    • Pinia利用Vue 3的Reactivity系统自动追踪依赖,减少不必要的渲染。
    • Vuex的依赖追踪可能不如Pinia高效,尤其是在复杂的状态变化场景中。

结论

选择Vuex还是Pinia,取决于你的项目需求、团队熟悉度以及个人偏好。对于追求最新技术和简洁代码的新项目,Pinia可能是更好的选择;而对于维护已有使用Vuex的大型项目,可能继续使用Vuex会更加稳定和经济。无论哪种选择,都应确保团队成员能够充分理解和掌握所选状态管理库的核心概念和最佳实践。

转载自:https://juejin.cn/post/7394289267265126452
评论
请登录