You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
classStore{registerModule(path,rawModule,options={}){if(typeofpath==='string')path=[path]this._modules.register(path,rawModule)installModule(this,this.state,path,this._modules.get(path),options.preserveState)// reset store to update getters...resetStoreVM(this,this.state)}}
Vuex原理
Vuex是什么?
以上是Vuex官方的说明。
从使用者角度来讲,Vuex是管理组件共享数据的一种可选方案,该方案定义了一套state、getter、mutation、action概念及规则,并实现了模块化的数据管理。
Vuex的基本原理有三部分:全局共享状态、状态管理、模块管理。
全局共享状态
当我们需要用到Vuex管理的状态时,会这样用
this.$store
就是被全局共享的对象,该对象是通过以下步骤创建并设置的。至此,
Vuex.Store
实例可以在Vue
实例上访问到。但是,在
Vue
实例内,还只能通过this.$root.store
获取。实现Vue
实例内全局共享的关键是Vue提供的安装插件方法:这一步实际上会执行
Vuex.install(Vue)
,该方法执行了以下内容:状态管理
Vuex的状态管理分为4个概念:
其中,state、getters是Vue组件内常用的读取状态的属性集合,mutations、actions是Vue组件内常用的更新状态的方法集合。
当我们使用Vuex来进行状态管理,会这样用:
实例化过程中,
options
的内容会被Vuex读取并进行以下操作:创建命名空间,在后一节“模块管理”中具体说明;
遍历
getters
,包装为接收局部state
、局部getters
、全局state
、全局getters
为参数的新函数并存储;state
与存储的getters
一起,通过创建新的Vue
实例进行存储。对外则通过设置取值器提供访问;
遍历
mutations
,包装为接收局部state
、提交载荷
的新函数并存储;遍历
actions
,包装为返回Promise
的新函数并存储。如果存在子模块,则对子模块遍历并逐个递归这一过程。
模块管理
命名空间
Vuex使用“模块”来对
store
进行分割,模块内默认操作当前模块的状态,也可以访问全局状态,还可以通过命名空间访问其他模块的局部状态。这行代码即派发了三级模块
module
的actions.foo()
方法。对于
dispatch
而言,它只是派发了名为'some/nested/module/foo'
的已存储的方法,而方法命名的的过程是在Vuex实例化过程中安装模块时完成的。在对子模块进行遍历递归安装过程中,只有模块路径
path
和配置对象child
会发生变化,path
是命名的依据。局部状态
Vuex的状态管理始终是统一的、全局的,其创建的状态树是唯一的。“局部状态”是访问状态树的一块局部,即分别对state、getters、commit、dispatch进行修改:
Object.defineProperty
设置local.state
、local.getters
的取值器local.commit()
、local.dispatch()
方法,闭包存储当前命名空间,自动地为传入的参数加上该命名空间得到的
local
对象会在上一节mutations
、actions
包装函数时作为入参使用。更多具体实现可以查看笔者上一篇《Vuex源码解析》
应用场景
共享状态的目的就是为了进行通信。Vue组件通信方式默认是父子组件间通信,非父子组件通信要么转换成多级的父子组件间通信,要么使用全局变量进行状态管理,Vuex提供了第三种方案:创建一个在Vue实例间共享的单例进行状态管理。
下面用伪代码的方式描述下三者的区别:
多级的父子组件通信、全局变量、Vuex,三种方式都能达到Vue组件通信的目的。
多级的父子组件通信显然不是一个合适的解决方案,因为修改通信过程要改多处功能不相关的组件代码。全局变量、Vuex都能够脱离组件层级地实现通信,但是全局变量由于简单、缺少约束,随着项目的持续迭代,容易出现重复命名导致的问题,Vuex则没有这样的问题,因此是三种方式中功能比较完善的方式。
然而,完善的功能是建立在使用体验良好的API封装上的,未必是性能优先的。尽管Vuex小心地只维护唯一状态树,但API封装的过程中的遍历、递归、Object.defineProperty、函数包装等等行为,不可避免地产生了性能消耗,这种消耗在特定场景下会表现出性能问题。
坑:模块动态注册
模块动态注册的实现逻辑很简单:
坑的关键在于
resetStoreVM()
方法,该方法内容是创建新的Vue
实例来进行状态管理。每次执行
resetStoreVM()
都将执行vue实例化过程以创建一棵新的状态树,替代原有状态树,每个动态注册模块的过程都会重复这一步。在Vue实例化过程中,
state
对象会被递归地使用Object.defineProperty()
转换为响应式,尽管Vuex通过直接将对象赋值给data
以复用原有状态树进行优化,这仍然是高耗性能的,意味着你最好避免多次调用resetStoreVM()
方法,而应当考虑合并多个需要动态注册的模块以减少调用次数。The text was updated successfully, but these errors were encountered: