[React] 07 - Flux: uni-flow for react
相关资源
Ref: [Android Module] 03 - Software Design and Architecture
Ref: Flux 架构入门教程
Ref: 详解React Flux架构工作方式
Ref: 阮一峰
*** Redux 和 Flux 很像 ***
主要区别在于Flux有多个可以改变应用状态的store,它通过事件来触发这些变化。【store较多】
组件可以订阅这些事件来和当前状态同步。
- Redux 没有分发器dispatcher,
- Flux 中dispatcher被用来传递数据到注册的回调事件。
另一个不同是Flux中有很多扩展是可用的,这也带来了一些混乱与矛盾。
*** 下一步 ***
(1) Redux
Goto: 《看漫画,学 Redux》
你以为Redux就是终结了么? NO, NO, NO!
(2) redux-saga又是什么鬼?
redux-saga 是一个 redux 的中间件,而中间件的作用是为 redux 提供额外的功能。
框架结构
Flux将一个应用分成四个部分,对,我们故意将代码写成这种单向流的逻辑形式。
- View: 视图层
- Action(动作):视图层发出的消息(比如mouseClick)
- Dispatcher(派发器):用来接收Actions、执行回调函数
- Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面
$ git clone https://github.com/ruanyf/extremely-simple-flux-demo.git
$ cd extremely-simple-flux-demo && npm install
$ npm start
示范代码下载
代码演示
一、"controll view" 模式
(1) MyButton,不包含状态,
是一个纯组件,从而方便了测试和复用。(2) MyButtonController,只保存状态,
将参数传给子组件MyButton。
Ref: React中的无状态和有状态组件
无状态组件:无状态组件(Stateless Component)是最基础的组件形式,由于没有状态的影响所以就是纯静态展示的作用。一般来说,各种UI库里也是最开始会开发的组件类别。如按钮、标签、输入框等。它的基本组成结构就是属性(props
)加上一个渲染函数(render
)。由于不涉及到状态的更新,所以这种组件的复用性也最强。
有状态组件:在无状态组件的基础上,如果组件内部包含状态(state
)且状态随着事件或者外部的消息而发生改变的时候,这就构成了有状态组件(Stateful Component)。有状态组件通常会带有生命周期(lifecycle),用以在不同的时刻触发状态的更新。这种组件也是通常在写业务逻辑中最经常使用到的,根据不同的业务场景组件的状态数量以及生命周期机制也不尽相同。
button如何跟这个状态扯上了关系?思考下如果自己实现会采用怎样的思路?
二、代码解读
(1) 可见是个“纯组件”的代码,方便独立测试!
一旦用户点击,就调用this.createNewItem
方法,向Dispatcher发出一个Action。
一问:props.onClick在哪里?
答:button的onClick指向了外边的MyButton的onClick的内容,也就是createNewItem。
二问:为什么这么做?
如此,状态就可以独立在button的外边,button就是个“纯组件”了。
(2) 将“状态”转发给子组件,并发一道命令(action) 给store。
// components/MyButtonController.jsx
var React = require('react');
var ButtonActions = require('../actions/ButtonActions');
var MyButton = require('./MyButton'); var MyButtonController = React.createClass({
createNewItem: function (event) {
ButtonActions.addNewItem('new item'); // ----> 调用createNewItem
方法,会触发名为addNewItem
的Action。
}, render: function() {
return <MyButton
onClick={this.createNewItem} // <---- 赋具体的onClick,也即是干活的地方
/>;
}
}); module.exports = MyButtonController;
找到了干活的地方(改变状态的地方),但具体的事该怎么去做,是交给了下面的action来处理,也即是发了“一道命令”。
(3) 把动作ADD_NEW_ITEM
派发到Store,看上去:dispatch就会与switch紧密相连。
var AppDispatcher = require('../dispatcher/AppDispatcher'); var ButtonActions = {
addNewItem: function (text) {
AppDispatcher.dispatch({ // ButtonActions.addNewItem方法,使用AppDispatcher
,把动作ADD_NEW_ITEM
派发到Store
actionType: 'ADD_NEW_ITEM',
text: text
});
},
}; module.exports = ButtonActions;
(4) 看作是一个路由器,负责在 View 和 Store 之间,建立 Action 的正确传递路线。
注意,Dispatcher 只能有一个,而且是全局的。
Jeff:
这里调用了store的具体改变state的函数,如此,函数其实就都集中写在了store里。
如何正确的判断request来调用store里的函数,也即是"router"问题,便是dispatch的事儿。
var Dispatcher = require('flux').Dispatcher;
var AppDispatcher = new Dispatcher();
var ListStore = require('../stores/ListStore');
/**
* 全局性的注册,因为dispatcher只能有一个
*/
AppDispatcher.register(function (action) {
switch(action.actionType) {
case 'ADD_NEW_ITEM':
ListStore.addNewItemHandler(action.text); // 执行回调函数,对ListStore
进行操作
ListStore.emitChange(); // 触发“change”事件,在哪里监听到了呢?
break;
default:
// no op
}
}) module.exports = AppDispatcher;
可见,来什么actionType,就分配对应的函数去干活;具体改变状态的函数在接下来的store里面。
(5) Store 改变 并 保存着整个应用的状态,也就是具体干活的地儿。
// stores/ListStore.js
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
/**
* Store 需要在变动后向 View 发送"change"事件,因此它必须实现事件接口
*/
var ListStore = assign({}, EventEmitter.prototype, {
items: [], getAll: function () {
return this.items;
}, addNewItemHandler: function (text) {
this.items.push(text);
}, emitChange: function () {
this.emit('change'); // --> 触发事件
},
-------------------------------------------------------
addChangeListener: function(callback) {
this.on('change', callback); // <-- 监听事件
}, removeChangeListener: function(callback) {
this.removeListener('change', callback);
}
}); module.exports = ListStore;
(6) 补充上View中的监听事件
可见,在(2)的MyButtonController中,还少了什么:监听“change"触发时间的listener。
var React = require('react');
var ListStore = require('../stores/ListStore'); // 添加
var ButtonActions = require('../actions/ButtonActions');
var MyButton = require('./MyButton'); var MyButtonController = React.createClass({ ----------------------------------------------------------
getInitialState: function () {
return {
items: ListStore.getAll()
};
}, componentDidMount: function() {
ListStore.addChangeListener(this._onChange);
}, componentWillUnmount: function() {
ListStore.removeChangeListener(this._onChange);
}, _onChange: function () { // <---- listener
this.setState({
items: ListStore.getAll()
});
},
----------------------------------------------------------
createNewItem: function (event) {
ButtonActions.addNewItem('new item');
}, render: function() {
return <MyButton
items={this.state.items} // 添加
onClick={this.createNewItem}
/>;
} }); module.exports = MyButtonController;
[React] 07 - Flux: uni-flow for react的更多相关文章
- 使用 React 和 Flux 创建一个记事本应用
React,来自 Facebook,是一个用来创建用户界面的非常优秀的类库.唯一的问题是 React 不会关注于你的应用如何处理数据.大多数人把 React 当做 MV* 中的 V.所以,Facebo ...
- 【转】浅谈React、Flux 与 Redux
本文转自<浅谈React.Flux 与 Redux>,转载请注明出处. React React 是一个 View 层的框架,用来渲染视图,它主要做几件事情: 组件化 利用 props 形成 ...
- react及flux架构范例Todomvc分析
react及flux架构范例Todomvc分析 通过分析flux-todomvc源码,学习如何通过react构建web程序,了解编写react应用程序的一般步骤,同时掌握Flux的单向数据流动架构思想 ...
- 理顺react,flux,redux这些概念的关系
作者:北溟小鱼hk链接:https://www.zhihu.com/question/47686258/answer/107209140来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...
- [React] Remove React PropTypes by using Flow Annotations (in CRA)
Starting from v15.5 if we wanted to use React's PropTypes we had to change our code to use a separat ...
- React学习笔记-1-什么是react,react环境搭建以及第一个react实例
什么是react?react的官方网站:https://facebook.github.io/react/下图这个就是就是react的标志,非常巧合的是他和我们的github的编辑器Atom非常相似. ...
- React系列(一):React入门
React简介 1.由来 React是有Facebook开发出来用于构建前端界面的JS组件库,由于其背后的强大背景,使得这款库在技术开发上完全没有问题. 2.React的优势 解决大规模项目开发中数据 ...
- React Native是一套使用 React 构建 Native app 的编程框架
React Native是一套使用 React 构建 Native app 的编程框架 React Native at first sight what is React Native? 跟据官方的描 ...
- react.js 从零开始(七)React (虚拟)DOM
React 元素 React 中最主要的类型就是 ReactElement.它有四个属性:type,props,key 和ref.它没有方法,并且原型上什么都没有. 可以通过 React.create ...
随机推荐
- 前端框架React Js入门教程【精】
现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领 ...
- [java web]Idea+maven+spring4+hibernate5+struts2整合过程
摘要 最近也在网上找了些教程,试着使用maven进行包依赖关系的管理,也尝试着通过注解的方式来整合ssh框架.在这个过程中,踩了不少的坑.折腾很长时间,才算把架子折腾起来.这里把结果整理下,作为以后工 ...
- 奇怪吸引子---RayleighBenard
奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...
- 【设计模式】jdbc桥连接过程解析
读多少源码,便知自己有多无知! 想温习一下桥链接模式,然后觉得自己已然吃透了,因为自己写的博客,觉得还是应该更具体一些. 类似于这样的结构: 个人理解: 模式类型:概述:角色:模式的应用场景:结 ...
- 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧
案例背景与需求介绍 之前做过一个美国的医疗保险的项目,保险提供商有大量的文件需要发送给比如像银行,医疗协会,第三方服务商等.比如像与银行交互的 ACH 文件,传送给协会的 ACH Credit 等文件 ...
- sublime text3怎么安装Package Control
sublime text3地址:https://packagecontrol.io/installation#st3 1.打开Preferences——Browse Packages,打开一个文件夹C ...
- mysql存储引擎的一点学习心得总结
首先我们应该了解mysql中的一个重要特性--插件式存储引擎,从名字就能够看出在mysql中,用户能够依据自己的需求随意的选择存储引擎.实际上也是这样.即使在同一个数据库中.不同的表也能够使用不同的存 ...
- Rocket Typist for Mac(增强型文本快速输入工具)破解版安装
1.软件简介 Rocket Typist 是 macOS 系统上一款增强型文本快速输入工具,我们可以利用这款工具预先设置保存好很多日常生活学习或是工作中常用的文本片段,还能设定部分内容为变量,当 ...
- Effective Java 第三版——52. 明智而审慎地使用重载
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Appium 输入 & 符号,实际输入&-
2018-10-11 12:27:12:178 - [debug] [MJSONWP] Calling AppiumDriver.setValue() with args: [["& ...