- 内容简介
- 译者序
- 前言
- 第 1 章 安装配置新项目
- 第 2 章 Flexbox 布局介绍
- 第 3 章 用 React Native 开发一个应用
- 第 4 章 在 React Native 中使用导航
- 第 5 章 动画和滑动菜单
- 第 6 章 用 React Native 绘制 Canvas
- 第 7 章 使用 React Native 播放音频
- 第 8 章 你的第一个自定义视图
- 第 9 章 Flux 介绍
- 第 10 章 处理复杂的应用程序状态
- 第 11 章 使用 Node 来实现服务端 API
- 第 12 章 在 React Native 中使用文件上传
- 第 13 章 理解 JavaScript Promise
- 第 14 章 fetch 简介
- 第 15 章 在 iOS 中使用 SQLite
- 第 16 章 集成 Google Admob
- 第 17 章 React Native 组件国际化
- 附录 A React.js 快速介绍
- 附录 B Objective-C Primer
- 附录 C webpack 入门
Flux 代码
你会在 Flux 的官网看到这张图片:

现在,我们把上面使用 ReactJS 写的 Todo 示例用 Flux 重写。
创建一个文件结构,包含一个 TodoStore、一个 TodoStoreAction 和两个 Dispatcher。
完整代码
下面是要用到的所有代码,最开始的部分是安装 es6-promise:
npm install object-assign es6-promise --save
dispatcher/Dispatcher.js
var Promise = require('es6-promise').Promise;
var assign = require('object-assign');
var _callbacks = [];
var _promise = [];
var Dispatcher = function(){};
Dispatcher.prototype = assign({}, Dispatcher.prototype, {
/**
* 注册函数
* 注册一个
Store 的回调函数,这样它就可以在一个
action 发生时被调用
* @param {function} callback 需要注册的回调函数
* @return {number} 该回调函数在
_callbacks 数组中的索引
*/
register: function(callback) {
_callbacks.push(callback);
return _callbacks.length - 1; // index
},
/**
* 派发函数
* @param {object} payload 从
action 拿到的数据
*/
dispatch: function(payload) {
// 首先创建引用回调函数的
promise 数组
var resolves = [];
var rejects = [];
_promises = _callbacks.map(function(_, i) {
return new Pormise(function(resolve, reject){
resolves[i] = resolve;
rejects[i] = reject;
});
});
// 派发给回调函数并处理
promise
_callbacks.forEach(function(callback, i) {
// 回调可能返回一个
obj 对象或者
promise
// 可以参考
waitFor(),来理解为什么这么做可能有用。
Promise.resolve(callback(payload)).then(function(){
resolves[i](payload);
}, function(){
rejects[i](new Error('Dispatch callback unsuccessful'));
});
});
_promises = [];
}
});
module.exports = Dispatcher;
dispatcher/AppDispatcher.js
var Dispatcher = require('./Dispatcher');
var assign = require('object-assign');
var AppDispatcher = assign({}, AppDispatcher.prototype, {
handleViewAction: function(action) {
this.dispatch({
source: 'VIEW_ACTION',
action: action
});
}
});
module.exports = AppDispatcher;
actions/TodoStoreActions.js
var AppDispatcher = require('../dispatcher/AppDispatcher');
var TodoStoreActions = {
loadTodos: function(){
var todos = [
{id: 1, content: 'todo1'},
{id: 2, content: 'todo2'},
{id: 3, content: 'todo3'}
];
AppDispatcher.handleViewAction({
actionType: 'LOAD_TODOS',
data: {
todos: todos
}
});
}
};
module.exports = TodoStoreActions;
stores/TodoStore.js
'use strict'
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
// todos 数组对象
var _todos = [];
// 从
data action 中加载
todos 数据的方法
function loadTodos(todos){
_todos = data.todos;
}
// 使用
Node 的
Event Emitter 来合并我们的
store 数据
var TodoStore = assign({}, EventEmitter.prototype, {
// 返回所有的
todos 数据
getTodos: function() {
return _todos;
},
emitChange: function() {
this.emit('change');
},
addChangeListener: function(callback) {
this.on('change', callback);
},
removeChangeListener: function(callback) {
this.removeListener('change', callback);
}
});
// 注册
dispatcher 的回调函数
AppDispatcher.register(function(payload){
var action = payload.action;
// 定义不同
action 的执行逻辑
switch(action) {
case 'LOAD_TODOS':
// 根据分发的
action 来调用方法
loadTodos(action.data);
break;
default:
return true;
}
// 如果
action 已经生效,发布
change 事件
TodoStore.emitChange();
return true;
});
module.exports = TodoStore;
main.js
'use strict'
var React = require('react');
var TodoList = require('./components/TodoList');
var TodoStoreActions = require('./actions/TodoStoreActions');
var TodoStore = require('./store/TodoStore');
// 从
store 中获取应用状态的方法
function getAppState() {
return {
todos: TodoStore.getTodos()
};
}
var TodoApp = React.createClass({
getInitialState: function() {
TodoStoreActions.loadTodos();
return getAppState();
},
componentDidMount: function() {
TodoStore.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
TodoStore.removeChangeListener(this._onChange);
},
addTodo: function() {
},
render: function() {
return (
<div>
<input type="text" ref="todo" />
<button onClick={this.addTodo}>Add</button>
<h2>Todos:</h2>
<TodoList items={this.state.todos} />
</div>
);
},
_onChange: function() {
this.setState(getAppState());
}
});
React.render(<TodoApp />, document.getElementById('example'));
多么冗长的代码!我把所有代码先贴出来,是为了让读者在真正了解代码意思之前先对整体有个直观印象。下面我们进入解释环节。
代码解释 1
你会在 TodoApp 的 getInitialState 方法中看到如下代码:
getInitialState: function() {
TodoStoreActions.loadTodos();
return getAppState();
}
你应该知道,我们总是使用源于视图(View)的 Action 作为一个命令或查询。但是辅助方法 getAppState 是个例外,我们可以通过它直接获得 TodoStore 的数据。因为 TodoStore 作为应用中唯一可以改变数据的地方,它保存了当前应用状态的快照,所以任何时候 TodoStore 触发 change 事件,视图都会重新渲染:
componentDidMount: function() {
TodoStore.addChangeListener(this._onChange);
},
// 解除
change 事件监听器
componentWillUnmount: function() {
TodoStore.removeChangeListener(this._onChange);
},
_onChange: function() {
this.setState(getAppState());
}
任何时候,TodoStore 触发 change 事件,都会引起视图(View)中的回调函数执行,在这里回调函数是_onChange 方法。TodoStore 继承自 EventEmitter,所以允许其他对象监听它的事件。
代码解释 2
现在开始解释调度器(Dispatcher)。
一旦 View 调用了 TodoStoreActions 的方法,TodoStoreActions 就会调用 dispatch 方法。调度器将通过 action 来调用相应 store 的方法。
当在 TodoStoreActions 中调用了如下方法后:
AppDispatcher.handleViewAction({
actionType: 'LOAD_TODOS',
data: {
todos: todos
}
});
AppDispatcher 将会自动调用已经注册的回调方法:
AppDispatcher.register(function(payload){
var action = payload.action;
// 定义不同
action 的执行逻辑
switch(action) {
case 'LOAD_TODOS':
// 根据分发的
action 来调用方法
loadTodos(action.data);
break;
default:
return true;
}
// 如果
action 已经生效,发布
change 事件
TodoStore.emitChange();
return true;
});
当 TodoStore 触发了 change 事件,视图就会重新渲染。
简而言之,这一过程可以总结如下:
React View==[ 发起 ]→Action==[ 调度 ]→Dispatcher==[ 执行回调 ]→Store==[ 触发 change 事件 ]→React View[ 重新渲染视图 ]
到这里,我们就结束了 Flux 应用的架构介绍。下一章,我们将把本例的 HTML/JavaScript 代码改造成 React Native 的代码。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论