源码分析vuex如何维护多个组件的数据共享

284 阅读3分钟

  之前分析了vue组件之间的关系,每个组件都是一个独立的实例,那么涉及到组件之间的通信大概可以分为以下几种情况:
1.父子组件的通信:父组件向子组件传递props,子组件向父组件冒泡事件。
2.兄弟组件间的通信:子组件先传值给父组件,然后再通过父组件传递给另一个子组件。或者通过一个事件总线组件来传递事件。(如果想深入了解可以自行百度,这里就不深入讨论)
3.组件关系复杂:将共享的数据抽出来,放到全局。这个用来存放共享数据的唯一数据源,就是vuex中的 Store。
  在分析完子组件渲染流程后,我们从源码中来看一下vuex是如何维护多个组件间的数据共享的。本次分析不会深入分析vuex内部实现,重点在于如何与vue之间配合完成vue多个组件间的状态共享。首先我们先从vuex官方代码example中的用法来看一下vuex是如何应用的:
  在项目的入口文件中,我们引入了store文件夹中的index.js,然后将引入的store作为初始化Vue的一个option元素对vue初始化。

  下面我们来看在store/index.js中vuex具体做了什么。首先引入了vuex,调用vue.use时传入了vuex。最后实例化Vuex.Store并导出模块。

  下面再来看下vuex的源码,来了解以下为什么这样引入vuex。在index.js中从store.js文件中引入了Store和install。

  在store.js文件中我们看到导出了Store类和install函数,其中Store类就是vuex的store实例的类,install函数是用来安装vuex的函数。

  在install函数中,判断了当前传入的vue实例_Vue是否是之前调用install时缓存的vue实例,如果是同一个实例,就返回警告。

  对比vue源码中的use API,这是vue引入插件和组件的常用方式,在这个方法中会调用插件的install方法。

  在install函数中调用了applyMixin函数,是在mixin.js中引入的。在导出的函数中如果是vue2,那么通过Vue.mixin全局混入了一个beforeCreate的钩子函数。在钩子函数中,通过vuexInit把初始化vue实例的options中的store挂载到了vue实例的store上,这也就是为什么在实例中可以通过$store访问到store实例。

那么在vue的父子组件中是怎样都是通过访问组件的$store元素访问到同一个store的呢?我们可以参考之前的公众号文档《通过keep-alive实现了解vue组件实现原理(1)》和《通过keep-alive实现了解vue组件实现原理(2)》其中有讲过,在子组件构造vnode阶段,会继承根组件的构造函数,继承方法如下图,比较重要的有在子组件的构造函数中执行根组件的_init初始化函数,在后续构造真实DOM节点的时候,实例化这个子组件的时候会执行。之后把被继承的组件的option合到了构造函数的options中。其中就包括了文章开头初始化vue时传入的store。

在真正初始化子组件的时候,走_init方法,如果是组件需要走initInternalComponent来合并options.

在initInternalComponent方法中,直接通过构造函数的options构造了一个对象,赋值给了vm.$options,通过构造函数完成了父组件options的传递,当然也包括了options中的store。

就这样回到_init函数后,子组件通过执行beforeCreate钩子,把store也挂载到了自己的$store上面。

更多精彩文章请关注