为什么我们需要 Vuex

3,762 阅读2分钟

一、一个错误引发的思考

在 Weex 子组件中通过 this.$parent.$emit('event') 触发父组件的事件,父组件通过 this.$on('event', handler) 接收事件,从而实现父子组件的通信。这在 Native 端表现正常,然而当使用 Vue-loader 编译代码,引入 vue-runtimeweex-vue-render 在浏览器端运行的时候,事件无法正常捕获,这是什么原因呢?

假设把前文所说的父组件命名为 father, 子组件命名为 child,起初, Weex 中:

    child.$parent === father // true

我们为了通知 father 去做某件事情,可以在 child 中使用 this.$parent.$emit,可是当解析到浏览器执行的时候,Debugger 发现:

    child.$parent === father // false
    child.$parent.$parent === father // false

也就是在 father 和 child 之间,多了一层组件的封装,之前的父子关系发生了改变,事件自然无法正常传达

这是因为,在 Weex 中有很多内建组件,底层基于 Native 端实现,当通过 vue-runtime 在浏览器运行的时候,需要将这些内建组件用基于浏览器的 Vue 组件代替,而这些 Vue 组件要实现类似底层 Native 组件的效果,极有可能需要封装多层,也就是会出现上述的父子关系变更的情况

可以认为是 Weex 做得不好的地方,但是我觉着,就算没有这个错误,也应该避免使用
this.$parent

二、this.$parent 背离了组件解耦的原则

上述的组件通信方式,是从哪来的奇淫巧技,我都已忘记,目前在 Vue 官网上找不到这种使用方法,也就是连官方都不推荐了更印证了不应该使用 this.$parent 的说法。

其实原因也很简单,子组件引用父组件的实例,这种强关联背离了组件的解耦原则,子组件依赖于某一特定的父组件,那么这个子组件只适用在这个父组件下,把这个子组件放到别处,就无法正常运行(或者有功能的缺失),并且一旦出现章节一中父子关系变更的情况,结果更加难以预料

那么子父组件确实是需要通信的时候,不使用 this.$parent 有什么替代方案么?答案是有的,Vue 中有个 bus 总线,子组件通过 bus.$emit把事件发到总线中,任何组件都可以监听这个事件。也就是子组件只负责触发事件,并不需要关心具体的处理组件。总线接收到事件信号后,发送到监听了该事件的组件处理

对于父到子的通信,父组件通过 props 向子组件传入参数,对于这个方向的数据流,我们却不用太担心的解耦的问题,因为父组件作为调用方只需要传递子组件需要的参数即可,子组件只需要关心参数,并不需要关心是谁在调用,同样可以顺利移植,完成解耦

从这个层面来说,从某种意义上说,单向数据流促进了组件间的解耦

三、这同样可以解释为什么我们需要 Vuex

以这个角度来观察 Vuex 以及所有单向数据流状态控制框架,是不是某种意义上的事件总线呢?

bus.png

store.png

其实 Vuex 不过是 Bus 更高级细致的实现而已,连官方文档也说了,有必要好好思考下你是否真的需要 Vuex,如果你的应用本身不复杂,其实只需要一个简单的 Bus 就够了

公众号:菲麦前端