一、Flux架构
二、例子
1.TodoApp.react.js
1 /** 2 * Copyright (c) 2014-2015, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 */ 9 10 /** 11 * This component operates as a "Controller-View". It listens for changes in 12 * the TodoStore and passes the new data to its children. 13 */ 14 15 var Footer = require('./Footer.react'); 16 var Header = require('./Header.react'); 17 var MainSection = require('./MainSection.react'); 18 var React = require('react'); 19 var TodoStore = require('../stores/TodoStore'); 20 21 /** 22 * Retrieve the current TODO data from the TodoStore 23 */ 24 function getTodoState() { 25 return { 26 allTodos: TodoStore.getAll(), 27 areAllComplete: TodoStore.areAllComplete() 28 }; 29 } 30 31 var TodoApp = React.createClass({ 32 33 getInitialState: function() { 34 return getTodoState(); 35 }, 36 37 componentDidMount: function() { 38 TodoStore.addChangeListener(this._onChange); 39 }, 40 41 componentWillUnmount: function() { 42 TodoStore.removeChangeListener(this._onChange); 43 }, 44 45 /** 46 * @return {object} 47 */ 48 render: function() { 49 return ( 50 <div> 51 <Header /> 52 <MainSection 53 allTodos={this.state.allTodos} 54 areAllComplete={this.state.areAllComplete} 55 /> 56 <Footer allTodos={this.state.allTodos} /> 57 </div> 58 ); 59 }, 60 61 /** 62 * Event handler for 'change' events coming from the TodoStore 63 */ 64 _onChange: function() { 65 this.setState(getTodoState()); 66 } 67 68 }); 69 70 module.exports = TodoApp;
2.TodoActions.js
1 /* 2 * Copyright (c) 2014-2015, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 * 9 * TodoActions 10 */ 11 12 var AppDispatcher = require('../dispatcher/AppDispatcher'); 13 var TodoConstants = require('../constants/TodoConstants'); 14 15 var TodoActions = { 16 17 /** 18 * @param {string} text 19 */ 20 create: function(text) { 21 AppDispatcher.dispatch({ 22 actionType: TodoConstants.TODO_CREATE, 23 text: text 24 }); 25 }, 26 27 /** 28 * @param {string} id The ID of the ToDo item 29 * @param {string} text 30 */ 31 updateText: function(id, text) { 32 AppDispatcher.dispatch({ 33 actionType: TodoConstants.TODO_UPDATE_TEXT, 34 id: id, 35 text: text 36 }); 37 }, 38 39 /** 40 * Toggle whether a single ToDo is complete 41 * @param {object} todo 42 */ 43 toggleComplete: function(todo) { 44 var id = todo.id; 45 var actionType = todo.complete ? 46 TodoConstants.TODO_UNDO_COMPLETE : 47 TodoConstants.TODO_COMPLETE; 48 49 AppDispatcher.dispatch({ 50 actionType: actionType, 51 id: id 52 }); 53 }, 54 55 /** 56 * Mark all ToDos as complete 57 */ 58 toggleCompleteAll: function() { 59 AppDispatcher.dispatch({ 60 actionType: TodoConstants.TODO_TOGGLE_COMPLETE_ALL 61 }); 62 }, 63 64 /** 65 * @param {string} id 66 */ 67 destroy: function(id) { 68 AppDispatcher.dispatch({ 69 actionType: TodoConstants.TODO_DESTROY, 70 id: id 71 }); 72 }, 73 74 /** 75 * Delete all the completed ToDos 76 */ 77 destroyCompleted: function() { 78 AppDispatcher.dispatch({ 79 actionType: TodoConstants.TODO_DESTROY_COMPLETED 80 }); 81 } 82 83 }; 84 85 module.exports = TodoActions;
3.AppDispatcher.js
1 /* 2 * Copyright (c) 2014-2015, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 * 9 * AppDispatcher 10 * 11 * A singleton that operates as the central hub for application updates. 12 */ 13 14 var Dispatcher = require('flux').Dispatcher; 15 16 module.exports = new Dispatcher();
4.TodoStore.js
1 /* 2 * Copyright (c) 2014, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 * 9 * TodoStore 10 */ 11 12 var AppDispatcher = require('../dispatcher/AppDispatcher'); 13 var EventEmitter = require('events').EventEmitter; 14 var TodoConstants = require('../constants/TodoConstants'); 15 var assign = require('object-assign'); 16 17 var CHANGE_EVENT = 'change'; 18 19 var _todos = {}; 20 21 /** 22 * Create a TODO item. 23 * @param {string} text The content of the TODO 24 */ 25 function create(text) { 26 // Hand waving here -- not showing how this interacts with XHR or persistent 27 // server-side storage. 28 // Using the current timestamp + random number in place of a real id. 29 var id = (+new Date() + Math.floor(Math.random() * 999999)).toString(36); 30 _todos[id] = { 31 id: id, 32 complete: false, 33 text: text 34 }; 35 } 36 37 /** 38 * Update a TODO item. 39 * @param {string} id 40 * @param {object} updates An object literal containing only the data to be 41 * updated. 42 */ 43 function update(id, updates) { 44 _todos[id] = assign({}, _todos[id], updates); 45 } 46 47 /** 48 * Update all of the TODO items with the same object. 49 * @param {object} updates An object literal containing only the data to be 50 * updated. 51 */ 52 function updateAll(updates) { 53 for (var id in _todos) { 54 update(id, updates); 55 } 56 } 57 58 /** 59 * Delete a TODO item. 60 * @param {string} id 61 */ 62 function destroy(id) { 63 delete _todos[id]; 64 } 65 66 /** 67 * Delete all the completed TODO items. 68 */ 69 function destroyCompleted() { 70 for (var id in _todos) { 71 if (_todos[id].complete) { 72 destroy(id); 73 } 74 } 75 } 76 77 var TodoStore = assign({}, EventEmitter.prototype, { 78 79 /** 80 * Tests whether all the remaining TODO items are marked as completed. 81 * @return {boolean} 82 */ 83 areAllComplete: function() { 84 for (var id in _todos) { 85 if (!_todos[id].complete) { 86 return false; 87 } 88 } 89 return true; 90 }, 91 92 /** 93 * Get the entire collection of TODOs. 94 * @return {object} 95 */ 96 getAll: function() { 97 return _todos; 98 }, 99 100 emitChange: function() { 101 this.emit(CHANGE_EVENT); 102 }, 103 104 /** 105 * @param {function} callback 106 */ 107 addChangeListener: function(callback) { 108 this.on(CHANGE_EVENT, callback); 109 }, 110 111 /** 112 * @param {function} callback 113 */ 114 removeChangeListener: function(callback) { 115 this.removeListener(CHANGE_EVENT, callback); 116 } 117 }); 118 119 // Register callback to handle all updates 120 AppDispatcher.register(function(action) { 121 var text; 122 123 switch(action.actionType) { 124 case TodoConstants.TODO_CREATE: 125 text = action.text.trim(); 126 if (text !== '') { 127 create(text); 128 TodoStore.emitChange(); 129 } 130 break; 131 132 case TodoConstants.TODO_TOGGLE_COMPLETE_ALL: 133 if (TodoStore.areAllComplete()) { 134 updateAll({complete: false}); 135 } else { 136 updateAll({complete: true}); 137 } 138 TodoStore.emitChange(); 139 break; 140 141 case TodoConstants.TODO_UNDO_COMPLETE: 142 update(action.id, {complete: false}); 143 TodoStore.emitChange(); 144 break; 145 146 case TodoConstants.TODO_COMPLETE: 147 update(action.id, {complete: true}); 148 TodoStore.emitChange(); 149 break; 150 151 case TodoConstants.TODO_UPDATE_TEXT: 152 text = action.text.trim(); 153 if (text !== '') { 154 update(action.id, {text: text}); 155 TodoStore.emitChange(); 156 } 157 break; 158 159 case TodoConstants.TODO_DESTROY: 160 destroy(action.id); 161 TodoStore.emitChange(); 162 break; 163 164 case TodoConstants.TODO_DESTROY_COMPLETED: 165 destroyCompleted(); 166 TodoStore.emitChange(); 167 break; 168 169 default: 170 // no op 171 } 172 }); 173 174 module.exports = TodoStore;