返回介绍

Flux 代码

发布于 2025-04-26 18:09:27 字数 6441 浏览 0 评论 0 收藏

你会在 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 的代码。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。