Ref: [Android Module] 03 - Software Design and Architecturehtml
Ref: Flux 架构入门教程react
Ref: 详解React Flux架构工做方式git
Ref: 阮一峰 github
*** Redux 和 Flux 很像 ***npm
主要区别在于Flux有多个能够改变应用状态的store,它经过事件来触发这些变化。【store较多】redux
组件能够订阅这些事件来和当前状态同步。架构
另外一个不一样是Flux中有不少扩展是可用的,这也带来了一些混乱与矛盾。并发
*** 下一步 ***框架
(1) Reduxless
Goto: 《看漫画,学 Redux》
你觉得Redux就是终结了么? NO, NO, NO!
(2) redux-saga又是什么鬼?
redux-saga 是一个 redux 的中间件,而中间件的做用是为 redux 提供额外的功能。
Flux将一个应用分红四个部分,对,咱们故意将代码写成这种单向流的逻辑形式。
$ git clone https://github.com/ruanyf/extremely-simple-flux-demo.git $ cd extremely-simple-flux-demo && npm install $ npm start
(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'); // ----> 调用方法,会触发名为的Action。 }, render: function() { return <MyButton onClick={this.createNewItem} // <---- 赋具体的onClick,也便是干活的地方 />; } }); module.exports = MyButtonController;createNewItemaddNewItem
找到了干活的地方(改变状态的地方),但具体的事该怎么去作,是交给了下面的action来处理,也便是发了“一道命令”。
(3) 把动做ADD_NEW_ITEM
派发到Store,看上去:dispatch就会与switch紧密相连。
var AppDispatcher = require('../dispatcher/AppDispatcher'); var ButtonActions = { addNewItem: function (text) { AppDispatcher.dispatch({ // ButtonActions.addNewItem方法,使用,把动做派发到Store actionType: 'ADD_NEW_ITEM', text: text }); }, }; module.exports = ButtonActions;AppDispatcherADD_NEW_ITEM
(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.emitChange(); // 触发“change”事件,在哪里监听到了呢? break; default: // no op } }) module.exports = AppDispatcher;ListStore
可见,来什么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;