EventBus & Vuex?
栏目: JavaScript · 发布时间: 5年前
内容简介:前几天有盆友在群里问,vue.$emit和$on可以跨组件完成全局通信,那岂不是可以完全代替vuex,为啥还要用vuex呢。这个问题就要从eventbu事件总线s和vuex起源说起了。(趁着尤大的vue3.0还在路上,我们来炒炒现饭)
前几天有盆友在群里问,vue.$emit和$on可以跨组件完成全局通信,那岂不是可以完全代替vuex,为啥还要用vuex呢。
这个问题就要从eventbu事件总线s和vuex起源说起了。
(趁着尤大的vue3.0还在路上,我们来炒炒现饭)
组件通信
在很久很久以前,在Vue王国里有一个组件塔,有一个组件家族,A,B,C,组件父亲A和儿子B,C生活在不同的层级之间,他们相隔非常远。
父->子
这个时候,父亲想念儿子了,想给他寄信,怎么办呢?简单!在每一个子组件上都有一个props “邮箱”,通过这个邮箱,父亲可以直接投递邮件(data)
Vue.component('blog-post', { // 在 JavaScript 中是 camelCase 的 props: ['postTitle'], template: '<h3>{{ postTitle }}</h3>' }) <!-- 在 HTML 中是 kebab-case 的 --> <blog-post post-title="我是父亲的消息!"></blog-post> 复制代码
子->父
收到父亲来信后,B,C都非常高兴。想给父亲回话,这时白鸽使者vue.$emit出来了,子组件用vue.$emit传递消息,往上层传播。
this.$emit("todo",{ res:"我是儿子的消息" }) 复制代码
接到消息后,父亲得对儿子传递过来的不同类型信息做出不同的回应
this.$on('todo',function(data){ // todo //data => 来自儿子的消息 }) 复制代码
兄弟
A经常教育B和C,说兄弟之间要多联系,增加感情,但是$emit又只能向上层传递消息,住在同一层的兄弟两又该怎么联系呢?
eventbu事件总线
这时候有一个智者想到了一个方法,既然你们都用$emit这个方法,我何不直接开个顺丰快递呢? 这时候vue eventbus事件总线出来了,利用一个游离在组件塔外的vue实例,构造了一个bus总线,儿子的消息通过$emit给bus总线.
B.$root.bus.$emit('todo') 复制代码
这时候父亲所得到的消息是由bus总线发出的,并设置响应事件
A.$root.bus.on('todo',function(){}) 复制代码
这样父亲儿子就可以轻轻松松的联系了
那最关键的问题是,兄弟之间怎么联系呢?
总线的智者这时候跳出来说,顾客就是上帝,不管是父亲儿子都可以使用我们顺丰快递总线,这样也就实现了兄弟组件之间的通信
B.$root.bus.$emit('todo') // 兄弟C也能收到这个消息 C.$root.bus.on('todo',function(){}) 复制代码
problem?
这个时候回到本文关键,为什么eventBus这么好的东西我们还要使用vuex呢?
最开始,我们的项目可能是简简单单这样的
在过了很长一段时间之后,王国不断发展,项目越来越大,组件塔里的组件越来越多,他们长得也越来越复杂,整个王国变得乱七八糟,项目结构变成下面这个样子。不同组件之间通信越来越多,代码段里不断的出现$emit和$on导致了以下几个主要问题
1. 代码逻辑性极具下降,可阅读性变低 2. 对于每一个action父组件都需要一个on(或dispatch)一个事件来处理 3. 你将很难查找到每一个事件是从哪里触发,满篇都是业务逻辑 复制代码
简单的例子
举个简单的例子。你的公司原来有一个display组件,他的作用是展现App根组件上increment的当前值。你新招了两个新员工,给他们分配了两个任务。
- 你让小A开发一个新的计数器在一个新的组件(childDisplay)里运用,实现点击一次增加increment一次,并在组件内展现increment当前的数字。这个计数器订阅了increment,点击计数器成功让display和childDisplay显示increment增加1后的数字。
小A开开心心迅速的完成了这个任务commit然后push了 - 你跟小B说,我需要一个按钮组件,这个按钮组件向app实例emit了一个reset事件,这个事件将重置App上increment为0
好的,小B也开开心心的commit然后push了 - 这个时候你会发现当你点击A组件时,在display和childDiplay上都成功显示了increment增加1以后的数字,但点击B组件触发reset事件时,根组件上的increment重置为了0,但由于小B并不知道A组件也订阅了increment这个数据,导致A组件状态没有更新。
vuex
为了防止这些问题,这个时候,国王尤小右站了出来,他借助隔壁flux王国的思想,带领全国的智者研究出了一个新的方式来解决这种混乱的问题。那就是vuex了。
按照定义来说
- store是一个仓库,仓库保存着项目的数据(store.state)
- (严格模式)为了解决无法追踪状态变化的问题,仓库里的数据不直接通过修改store.state来改变,而是通过commit一个动作告诉仓库,将会报错 [vuex] Do not mutate vuex store state outside mutation handlers
- 仓库收到了commit的动作后,将会在store.mutation里查找对应事件,并改变store.state
回到简单的例子
解决方案1(简单store模式)
为了解决上述问题,我们做出了几个有意思的改变。(state)
- 在store里定义了一个常量store
- 在本地数据里定义了一个叫做sharedState的变量,是store.state里的映射
- 因为sharedState是vue的数据,所以他让store.state也变成了一个响应式数据,当store.state里数据发生改变时,vue将会自动的更新sharedState里的数据。
这样,原有的问题就解决了,A组件和B组件订阅的increment不再是根组件上的数据了,而是仓库的数据。当仓库数据改变时,vue将自动更新到每个订阅了increment数据的组件上。
// 这是父级display组件 <template> Count is {{ sharedState.counter }} </template> <script> import store from '../store' export default { data () { return { sharedState: store.state } } } </script> 复制代码
// 这是A组件 import store from '../store' <template> Count is {{ sharedState.counter }} </template> export default { data () { return { sharedState: store.state } }, methods: { activate () { this.sharedState.counter += 1 } } } 复制代码
// 这是B组件 import store from '../store' export default { data () { return { sharedState: store.state } }, methods: { reset () { this.sharedState.counter = 0 } } } 复制代码
方案1变形
上述的方式就是最好的了吗?试想当A,B在这家公司开发了无数多个reset组件和计数器组件后离职了。这时候招来了一个新的员工C,你跟C说,我想要所有的increment大小不超过100,难道C要对所有组件进行重构,判断大小吗,这是非常荒谬的选择。这时候我们引入了新的方法。(mutation)
var store = { state: { counter: 0 }, increment: function () { if (store.state.counter < 100) { store.state.counter += 1; } }, reset: function () { store.state.counter = 0; } } export default store 复制代码
根据上面的衍生,vuex就慢慢成型了
我们重新创建store.js
import Vuex from 'vuex' import Vue from 'vue' Vue.use(Vuex) var store = new Vuex.Store({ state: { counter: 0 }, mutations: { INCREMENT (state) { state.counter ++ } } }) export default store 复制代码
我们看下这里做了什么样的操作
- 我们引入了一个vuex模块,并作为vue插件激活
- 我们的仓库store不再是一个普通的jsonObject而是一个vuex.store的实例
- 采用了mutation,用于改变state
why better ?
- 如果在开发过程中保留了所有状态的副本,我们可以像super hero一样如时空穿梭般对代码进行调试,记录每一次状态的变化
- 你可以构建一个中间件,比如一个日志打印器,在每次用户提交一个action时记录操作,当出现问题时你将会更加容易的调试与fix bug
- 强制要求你把所有action通过一个store管理,这样团队开发将会更加便捷与明了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Facebook效应
[美] 大卫·柯克帕特里克 / 沈路、梁军、崔筝 / 华文出版社 / 2010-10 / 49.80
本书作者近距离地采访了与Facebook相关的人士,其中包括Facebook的创始人、员工、投资人、意向投资人以及合作伙伴,加起来超过了130人。这是真切详实的访谈,更是超级精彩的故事。作者以其细腻的笔触,精巧的叙事结构,解密了Facebook如何从哈佛的宿舍里萌发,创始人的内讧,权力之争,如何放弃华盛顿邮报的投资,怎样争取到第一个广告客户,而第一轮融资又如何获得一亿美元的估值,让人痴迷的图片产品......一起来看看 《Facebook效应》 这本书的介绍吧!