Vuex的用法与源码学习
前言
在使用
vue
全家桶来开发前端站点的时候,对于vue组件间通信
,有那么一种方式(也是普遍使用的方式),就是使用vuex
来实现跨组件间的通讯,本文章旨在通过使用vuex
解决实际项目的同时,从源码层面解析关于vuex
是如何做到远程触发的相关原理的!Vuex
是一个专为Vue.js
应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
🌠 从上面可以看出这个vuex
的工作流是单向的,主要包含有3个元素:
- 状态(state): 驱动应用的数据源;
- 视图(view): 以声明方式将状态映射到视图;
- 操作(action): 响应在视图上的用户输入导致的状态变化
🌠 而实际在使用过程中,vuex
的设计理念是:把组件的共享状态抽取出来,以一个全局单例模式管理,组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为
Vuex的一般用法
😕 这里的一般流程如下:
源码分析
😕 这个
Store对象
是如何被“植入到”vue
实例中的呢?为什么可以在vue实例中就可以通过this.$store
来访问到?然后这个数据state更新了之后,为什么界面就会自动被更新到了呢?他与vue自带的数据双向绑定有什么区别呢?
👇 将具体分析一波!
相关成员
首先先来了解一下关于
Store
的成员
成员 | 类型 | 描述 |
---|---|---|
state | Object | 组件全局共享的data数据源 |
getters | 由函数组成的Object | 对state中的数据以及根/子module中的数据的计算属性函数所组成的对象 |
mutations | 由函数组成的Object | 成员函数主要负责接收来自对state中数据的更新操作 |
actions | 由函数组成的Object | 成员函数主要负责接受异步操作,并在操作后触发mutations中的方法来更新state中的数据 |
module | 由Store组成的Object | 根据业务场景拆分的不同模块 |
“远程”响应式触发是如何实现
1. 创建一个Vuex.Store
对象
1 | const store new Vuex.Store({ |
❓ 那么创建出来的Store
对象都有什么元素?它拥有什么功能?
从上面的关系图我们可以得出,Store体系主要由Store、ModuleCollection、Module三个部分来组成,下面来一个个分析一波:
Store
我们所编写的getters、mutations、actions对象所包含的函数对象,都存储在Store中,以命名空间来维护,存在这个Store对象中!
😕 那么,这里我们所维护的getters
、mutations
、actions
,它是如何存储在Store中的呢?
首先,在Store对象中都存储着 👇 几个属性
属性 | 描述 | 存储格式 |
---|---|---|
_actions | 存储的所有的action的对象 | { '命名空间+key': [一个个的函数] } |
_mutations | 存储的所有的mutation对象 | { '命名空间+key': [一个个的mumation] } |
_wrappedGetters | 存储的所有的getter函数所组成的对象 | { '命名空间+key': [一个个的getter函数对象] } |
那么,在 ☝ 这内容是如何被存储的呢?
⭐ 以mutation
为例:
1 | function registerMutation(store, type, handler, local){ |
从上面的代码,我们可以看出我们所维护的mutation
将会被以一个数组成员的方式被维护到_mutation
对象中,action
(只不过action是异步的)以及getter
也是如此!
ModuleCollection
模块收集管理类,主要负责对主模块以及各个子模块的管理,其中拥有一个属性(root,这是Module对象),代表着当前整个模块对象!
可以在这个root模块中,通过增删查改,根据key参数,来操作对应的模块
1 | export default class ModuleCollection{ |
Module
在
vuex
领域中的抽象module对象,每个Module对象都维护着自己的_children
子模块以及state
!
1 | export default class Module{ |
初始化整个state,设置监听的开始
同样的,从
Store.resetStoreVM()
方法开始
1 | function resetStoreVM(store, state, hot){ |
从 ☝ 的代码我们可以看出每一个store都new了一个Vue实例对象与之关联,因为一旦new了一个Vue实例对象,按照之前的学习,则会进行data函数中返回的对象的“响应化”包装
操作,也就是对这个state中的数据做了一个getter
+ setter
的监听,而当我们通过在界面元素中使用state
中的数据时,则会被自动更新,因为state已经被远程修改了,然后又是引用的同一个数据源,通过dep+watcher的依赖收集与依赖触发,因此界面就能够做到对应的响应式更新了
👉 也就是说,store中的state数据,都转换成为vue实例中的data,store中的getter,都转换为vue实例中的computed计算属性,然后一切又回到了原本的计算属性监听操作!
2. 通过Vue.use(store)
对象添加到vue实例中
1 | // 将store实例对象注册到vue实例中的$store属性中 |
🌠 从原本Vue的源码我们可以看出关于Vue.use()
动作的一个过程,其实就是调用的store中的install
方法,如下代码所示:
1 | export function initUse(Vue: GlobalAPI){ |
👉 而在vuex.install
方法中,又是直接调用自身的applyMixin(Vue)
,关于这个applyMixin(Vue)
方法定义如下:
1 | export default function(Vue){ |
3. 远程响应式更新的实现过程
未知较不常用的API
😕 在完成学习这个vuex的相关源码之后,发现在这个store对象中居然还有隐藏性的日常工作中为使用到的相关API以及属性:
- subscribe: 对
mutation
触发动作的监听,一旦有关于mutation的触发的话,将会直接触发设置的监听动作; - subscribeAction: 对
action
触发动作的监听,一旦有关于action动作的触发的话,将会直接触发设置的监听动作;
⚠ 要注意的是,在回调函数中不能直接修改state
,因为这样会破坏Vuex
的响应式原理。如果要修改state
,需要通过action
来触发mutation
的变化 - watcher: 对
getter
属性的触发动作的监听; - replaceState: 对整个
state
进行替换; - registerModule: 动态注册添加
module
,可实现在程序的运行过程中,针对这种情况,可以将待使用的module
已异步导入的方式来导入!
我学到了什么
- vue插件的定义
🌠 从 ☝ 的关于Vue.use
方法内容来看,通过以插件的方式来传入,并直接调用其中的install
方法,并传递Vue来作为install方法的参数,这里的需要理清楚关于args指的是什么! - 未完待续…