type
status
date
slug
summary
tags
category
icon
password
URL
1 Vuex 是什么?
在学习之前,我们先看看官方文档上的一张 Vuex 原理图:
从图上我们可以看到 DevTools(调试工具)、Vue Components(Vue组件)、Backend Api(调用后端 api)、Vuex 这四个主要元素。而 Vuex的核心是三大属性:
Actions、Mutations、State
官方文档不是有五个属性🐎?
是的,还有Modules、Getters。为什么图上没有后面两个元素,因为 Modules、Getters是用来辅助 Vuex的,真正的核心就是前面三个属性。
那这几个属性有什么区别?图上的几个属性结合图上的活动箭头又有什么猫腻?我们先来看一下
Vuex 骨架是怎么样:
下面我们将通过一个共享单车的例子一一讲解三个核心属性的操作是如何的?共享单车以两个组件为两个用户,点击相关开锁按钮文字变为锁车,剩余单车减一,点击锁车,剩余单车加一。怎么识别不同用户呢?这里以组件名为识别,当然真实环境是不行的,这里只是用于理解学习。
- state:中文意思:
状态
,它用来存放需要多个组件共用的变量的,从下面的代码可以看出 state 就是一个对象来的,我们在看看 state里面是个啥?其实它就是类似Vue实例的data属性
,只不过这里是用在Vuex 中的,与 data 一样为存储变量封装为响应式,有 get 和 set 方法。
- mutations:中文意思:
改变
,它用来操作state中变量的修改的,它也是一个对象用来定义修改变量操作的函数,而每个函数都有两个参数:state(状态)和value(要修改的值)。
- actions:中文意思:
行动
,它也是用来操作state 中变量的修改的,是一个对象用来封装定义执行 mutations里的函数,函数有两个参数:context 和 value(要修改的值)。那么 context是个啥?我们打印看看如下图,context有五个属性:state(若在模块中则为局部状态)rootState(等同state,只存在模块中), commit,dispatch,getters(等同getters),rootGetters(等同 getter 是,只存在模块中)。
那么问题来了,既然 mutations 与 actions功能都差不多,为什么会出现两个呢?官方的意思是同步代码与异步代码的区别,
mutation中支持同步代码,actions支持异步代码
。三个核心属性大概意思我们都知道了,那么dispatch 与 commit 两个动作的作用又是怎么样的?- dispatch:中文意思:
派遣
,一般在组件中调用,然后用来执行actions 中的函数,它又是个什么,参数 type 就是需要执行的 actions中的函数名,参数 payload 是新值,而 dispatch 是 vuex 源码中封装的一个函数。
- commit:中文意思:
提交
,一般在auctions 中调用,然后用来执行 mutations 中的修改函数,参数 type就是需要执行的 mutations 中的函数名,参数 payload 是新值,而 commit 是vuex 源码中封装的一个函数。
细心地我们有没有发现,根据 Vuex 原理图在组件中调用dispatch,其实它执行的就是 actions 里的函数,然后再去执行 commit 实现mutations 里的状态修改。那么问题来了?能不能直接 commit 实现mutations,其实是可以的,因为
mutation中支持同步代码,actions支持异步代码
,如果不是异步代码,我们可以直接在组件中调用commit 方法来实现 mutations,但是一般是推荐使用 actions 来处理 commit方法,方便代码统一,既然我们都实现 Vuex中的相关状态管理,下面我们看看组件中是如何处理状态的,下面以 test1组件为例:上面 Vuex 核心三个属性我们都知道了接下来了解 getters、modules属性:
- getters:用于将 state中的数据进行加工,其实它就是
类似Vue实例中的computed
,如将上面的共享单车文本内容抽取出来使用如下。
- modules:用于处理多个不同组件间通信模块化。如上面共享单车的处理,把共享单车的数量与用户数量分开模块处理。使用模块下的Vuex 状态管理代码如下:
模块化分为全局模块:存放全局使用共享的数据和局部模块:模块内单独管理,
全局模块不需要开启命名空间
。 好了好了,到了现在我们应该知道 Vuex 是什么了吧?Vuex 就是用来存储数据
的地方,最核心的技能就是共享
,什么情况下需要用到Vuex?
a,b 就是使用了允许命名空间的,如果没有设置 namespaced 为true,a,b 是不生效,只能直接引入对应 module 名。 下面是 test1组件中调用 Vuex 的代码如下:
- 多个组件依赖
同一状态
共享。
- 来自不同组件的行为需要变更
同一状态
共享。
2 Vue 优雅使用 Vuex
如果业务比较简单,没有涉及到多个组件多个状态的管理,单纯实现上面的Vuex就已经够用,但是如果使用场景更为复杂,我们就需要优化代码了,增强代码的维护,这就涉及到了mapState、mapGetters、mapMutations、mapActions。而这些属性的获取又分为两种情况:模块下和非模块下:
2.1 非模块下的 map~ 系列
- mapState:对 state中所有状态进行映射,也就是读取 state中所有状态,在组件中的计算属性直接使用,我们就可以直接在 template中直接使用状态了。
- mapGetters:对 getters中所有属性进行映射,也就是读取 getters 中所有属性,使用方式与 mapState使用方式一致。
- mapMutations:对 mutations所有属性函数进行隐射,也就是读取 mutations中所有属性方法。注意地
,如果需要传参数,直接在template中调用时直接传
。
- mapActions:对 actions所有属性函数进行隐射,也就是读取 actions 中所有属性方法。方式与 mapMutations 使用方式一致。
2.2 模块下的 map~ 系列
如果 Vuex 中是模块化管理的话,如果使用 map系列需要传两个参数:
模块名
和需要调用的对应属性里的属性
,注意地,如果开启了命名空间可以使用自定义地模块名比如下面例子的a、b,否则使用模块名如:bikeModules、userModules。各属性在组件中的使用情况如下:3 Vue3 优雅使用 Vuex
当前版本的 Vuex 实例化不通过 new Vuex.store({}) 实例化 Vuex了,是通过 createStore({}),Vuex 也不需要全局注册 store 了,在 setup中使用 useStore() 创建引入。在这里就不一一讲解了,用法与 vue2差不多,只是 Vue3 内部语法引入不一样了。
4 Vuex 进阶插件 pinia
4.1 pinia 是什么?
- pinia:Pinia 是 Vue专属状态管理库,它允许你跨组件或页面共享状态。可以看出,pinia 的功能与Vuex 功能是一样的,那么问题来了,既然有了 Vuex,为什么还要用pinia,这就需要考虑它的优点:
- 支持 Vue2、Vue3。
- 只有 state、getter、action 属性。
- pinia 的 action 支持同步和异步。
- 可以很方便访问其他 store 的 action。
- 良好的 ts 支持。
- 无需创建模块管理了。
- 体积非常小,只有 1kB 左右。
4.2 如何使用 pinia 插件?
- 在入口文件引入:
- 用 pinia 来再次使用上面的共享单车例子,pinia中没有模块化,它每创建一个 defineStore 就是单独一个 store,defineStore需要传两个参数,第一个参数是相当于每个 store 的id,第二个参数就是状态管理的核心了,代码如下:
从上面我们可以看出,相对于 Vuex,pinia插件的使用更方便而且更简洁了,没有 mutations属性,那么我们再看看在组件中是如何引入 pinia,下面也是以 test1组件为例子:
注意地,当使用store的过程中,如果直接对store进行解构,会破坏数据的响应,所以pinia提供了storeToRefs用来进行解构
Vuex 总结
- Vuex核心属性:state、mutations、actions,状态的管理主要是靠这三个属性,Vuex的核心操作是 dispatch 和 commit,而 Vuex的核心意义在于状态的共享,通过 state定义多个组件共享的变量,然后在 mutations中修改变量的值,同步异步都可以通过 actions 执行,dispatch可以通俗理解为执行 actions 中函数,commit 执行的是 mutations 中函数实现state 的状态改变。同步代码可以直接执行 dispatch。
- Vuex 的 mapState、mapMutations、mapActions、mapGetters系列都是用来优化 Vuex 代码的,方便我们进一步管理。
- Pinia 插件推荐使用,代码量减少了,更方便我们去使用 Vuex,简化了 Vuex结构,使用起来更加舒服爽滑。
参考资料
原po
- 作者:Orcatt
- 链接:https://orcatt.one/article/ba80290f-8597-4204-ad9b-6f973da0536e
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。