笔记----深入浅出《React和Redux》第三章Flux框架
书中的此章节“思想”类成分较多,需要理解的内容也相对较多,如果一一列举,本文就写的相对繁琐了,推荐有兴趣的同学可以去看一下书籍以及敲一下书中的代码,有助于理解作者大牛的思想,我就在此简略的记录一些相对重要的“点”了。
一、Flux框架的诞生以及解决了MVC框架哪些问题
1、Flux出现背景
Facebook的工程部门发现在前端使用MVC框架进行逻辑划分时,在业务量和代码量庞大的情况下,model层和view层之间依赖过于复杂,不利于后期对于代码的维护
理想中,各个模块分工:
Model:负责逻辑以及数据
View:负责渲染界面
Controller:负责接收用户的输入,根据用户的输入调用对应的Model部分逻辑,把产生的数据结果交给View部分,让View渲染出必要的输出
MVC框架的请求流程:用户请求------>Controller------>Model------>View,View和Model不能直接进行互相通信,都需要借助于Control
在实际工作中,对于浏览器端 MVC 框架,存在用户的交互处理,界面渲染出来之后,Model 和 View 依然存在于浏览器中,这时候就会诱惑开发者为了简便,让现存的 Model和 View直接对话,当代码量和逻辑复杂时,使程序“脆弱而且不可预测”
2、Flux框架
(1)特点:更严格的数据流控制
(2)各个模块:
Dispatcher(相当于“Controller”):用来接收Actions、执行回调函数;
Store(相当于“Model”):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面;
Action(相当于“用户请求”):视图层发出的消息;
View:显示用户界面;
(3)与MVC框架的区别:
(i)当系统需要扩充应用所能处理的“请求”时,在MVC中,通过在Controller增加函数,来实现扩充;
在Flux中,不需要Dispatcher增加新函数,而是通过增加新的Action类型,来实现扩充
(4)Flux实践 (直接上代码)
实现的效果:
当点击“+”按钮或者“-”按钮,对应行的数字会时时进行改变,并且总数也会时时改变,下图:
步骤一
安装Flux:npm install --save flux (如果感觉慢,可以安装国内淘宝镜像)
(i)Dispatcher
作用:生成Dispatcher实例,用来之后将 Action 派发到 Store
注意!注意! 注意!Dispatcher实例在全局只有一个
(ii)Action(分2个文件,一个定义action类型,另一个定义action构造函数)
ActionTypes.js
说明:将常量放在单独一个文件方便管理
Actions.js
作用:根据类型,生成不同的action对象,通过Dispatcher实例的dispatch函数派发出去
注意:出于业界习惯,这个文件被命名为Actions.js,但是要注意里面定义的并不是action对象本身,而是能够产生并进行派发action对象的函数
(iii)Store(创建了两个store,CounterStore是为Counter组件服务,SummaryStore是为总数服务)
CounterStore.js
说明:在CounterStore中可以看出,首先定义了Counter组件初始化的值,然后使用Object.assgin()函数,对EventEmitter.prototype对象进行了浅拷贝,并在此浅拷贝对象的基础上扩充了getCounterValues、emitChange、addChangeListener、removeChangeListener方法。其中这四个方法的后三个方法,分别调用了EventEmitter.prototype的on(),emit(),removeListener()方法,作用如下:
on(EVENT_TYPE,callback):用来监听事件,第一个参数是字符串事件类型,第二个参数是事件处理函数;
emit(EVENT_TYPE):用来触发事件,第一个参数是字符串事件类型;
removeListener(EVENT_TYPE,callback):用来移除事件,如果要调用removeListener函数,就一定要保留对处理函数的引用,
第一个参数是字符串事件类型,第二个参数是事件处理函数。
最后,通过把AppDispatcher.register()中的回调函数注册到Dispatcher上,来接受之前通过AppDispatcher.dispatch()派发的action对象,通过switch或if-else来实现对应类型的动作实现对应类型的操作。
SummaryStore.js
说明:总体代码和之前CounterStore差不多。需要说明的是在这两个store中,AppDispatcher.register()会返回一个标记,保存在各自store的dispatchToken字段中,用来之后实现多个store之间行为的依赖顺序,借助waitFor()。在这个代码中,我们希望SummaryStore的逻辑在CounterStore之后进行
作用: Store是一个对象,既用于存储应用状态,也用来接受Dispatcher派发的动作,根据动作决定是否更新应用状态。
注意:store 在Flux中可以存在多个,每一个 store 都会受到所有的 action 通知,然后自行觉得是否对这个 action 做出响应,更新 state;
store对外只暴露了读取接口,如果想实现写入的功能,只能去实现对应action。
(iv)View(用React进行实现,3个视图组件,其中ControlPanel父组件包含Counter子组件,Summary子组件)
ControlPanel组件
Counter
Summary
View 的代码就是常规React书写方式,就不一一叙述了
注意:存在于Flux框架中的React组件需要实现以下几个功能
1)创建时要读取Store上的状态来初始化组件内部状态;(而不像之前通过props传参,实现组件内部初始化)
2)当Store上状态发生变化时,组件要立刻同步更新内部状态保持一致;(通过Store改变状态后调用emit(),以及View通过on()来监听Store中状态的变化)
3)View如果要改变Store状态,只能派发action。(Flux中,对Store进行修改,只能通过新建action)
(v)上述代码个人理解及总结:
过程一:按着组件的生命周期函数顺序,进行渲染。其中componentDidMount函数通过CounterStore.addChangeListen函数监听了CounterStore的变化之后,只要CounterStore发生变化,Counter组件的onChange函数就自动会被调用。不过首次挂载时,可以发现getCounterValue被重复调用了2次来读取相同值,分别是第一个是constructor中被调用,第二个是componentDidMount中的this.onChange中被调用
过程二:当进行点击“+”按钮时,this.props.caption立即读取了当前组件上的属性值First,以形参的形式传入increment()方法,并触发increment();
(以First为例子)
过程三:此时Dispatcher的实例(AppDispatcher)调用dispatch()方法,将刚产生的action对象派发出去,此时action对象上携带着动作类型,以及刚刚传入的First字符串标记
过程四: 通过AppDispatche.register()来注册回调函数,之后这个回调函数就可以接受派发出来的action对象,并根据这个action对象的类型,执行对应的逻辑,即在这里的逻辑是根据action.counterCaption拿到First,然后通过counterValues[First]拿到当前保存在Store中的初始值,并进行加一操作,最后通过emit(),将事件触发
过程五:在过程一首次挂载时,onChange函数作为形参数,最终传入on()中,监听事件的触发,也就是等待emit函数被调用,然后执行onChange函数内部操作,通过getCounterValues获得Store的新状态值,即First字段加一后的值,最后通过setState函数将这个值同步到组件内部状态count上,同时State的更新会触发生命周期的shouldComponentUpdate函数,判断此次渲染是否与上一次不同,如果不同则返回true,并将结果渲染到页面
其他的“-”按钮以及计算总和的步骤流程也差不多,我就不继续进行描述了,可以按照上面过程进行推演。
结合自己理解,画了一个图,完毕。
3、Flux框架的优点:
(1)对比纯粹使用React框架,当多个组件或者组件之间多层嵌套的情况下,对一个全局变量进行操作,只通过props进行操作显的特别的麻烦,
在使用Flux框架情况下,React组件在其中只充当了View并对Store进行了时时的监听,全局变量由Store进行保存,组件可以通过action对Store进行操作,并反馈到View。
避免的props带来的繁琐,不过程序如果不复杂,使用Flux也可能把“简单问题复杂化”,使用时视情况而定。
(2)对比前端MVC框架,他的“单向数据流”管理方式更加的严格。
4、Flux框架不足:
(1) 多个Store之间的依赖
(2) Store混杂逻辑和状态
睡觉睡觉!!!!!!!未完待续~~~