【天赢金创】React flux九浅一深

这个是 Facebook 官方学习 Flux 的 todo 例子 javascript

想用这个例子来总结一下怎么从零开始用 React 和 Flux 构建一个 App css

Structure

App
├─ javascripts
│  ├─ actions
│  │  ├─ TodoActions.js
│  ├─ components
│  │  ├─ TodoComponents
│  │  │  ├─ TodoApp.js
│  │  │  ├─ Header.js
│  │  │  ├─ MainSection.js
│  │  │  ├─ Footer.js
│  │  │  ├─ TodoItem.js
│  │  │  ├─ TodoTextInput.js
│  ├─ constants
│  │  ├─ TodoConstants.js
│  ├─ dispatcher
│  │  ├─ AppDispatcher.js
│  ├─ stores
│  │  ├─ TodoStore.js
├─ stylesheets
│  ├─ TodoStyle.css
├─ index.html
├─ README.md
├─ package.json
├─ webpack.config.js

可能你看到的这个结构和官方 demo 的结构会有点不一样,那是由于官方的 demo 整个的自己只有 todo 这个功能,但实际上远远不至。因此在 components 下会细分是什么部分的组件,像 TodoComponents html

关于 Flux 里的 Action, Dispatcher, Store and Controller View 这些概念若是还不了解的话能够去看看这两篇文章 java

Components

首先你经过你 app 的界面来肯定你的组件,以下图 react

从这个图咱们能够看到,咱们的组件有 webpack

  • Header
  • MainSection
  • Footer
  • TodoItem
  • TodoTextInput

在 MainSection 里有 TodoTextInput 是当咱们双击咱们已经存在的 todo,能够对其进行更新 git

Actions

肯定了组件以后,咱们就能够肯定咱们的 TodoActions 文件了。 github

对于这个 Todo app,有多少 actions 呢? web

  • create - 咱们能够建立一条新的 todo
  • updateText - 双击已经存在的 todo,能够对其进行更新
  • toggleComplete - 看到每一条前面的勾勾了吗?就是能够给你决定是否完成了
  • toggleCompleteAll - 看到输入框前面那个 » 了吗?就是让你所有完成,或者所有不完成的
  • destroy - 看到每一条后面那个叉叉了吗?要 hover 在上面才看到的,就是给你删除这一条的
  • destroyCompleted - 看到 Footer 下面那个 Clear completed 了吗?就是给咱们删除已经完成的 todo 的

就是这样,咱们根据咱们的需求在这个文件里定义不一样的 action 函数,但这里的函数并不涉及逻辑的处理,这里函数只是告诉咱们的 Dispatcher,用户进行了什么操做。因此咱们只须要给 Dispatcher 传的一个对象,对象里一个必要的属性就是 actionType。若是用户进行这个操做有给咱们传的参数的话。那参数也会放在这个对象里。 npm

例如用户想建立一条新的 todo ,就是咱们的 create action 了

import AppDispatcher from '../dispatcher/AppDispatcher'; import TodoConstants from '../constants/TodoConstants'; var TodoActions = {
  create (text) {
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_CREATE,
      text: text
    });
  }, // other actions } export default TodoActions;

当咱们执行 AppDispatcher.dispatch 这个方法,并传给他一个有 actionType 属性的对象时,他就会在大喊,“有人作了一个操做呀,这个操做就是 xxx (actionType 的值),还带了个参数,大家哪一个来处理一下呀”

嗯嗯,就是这样,数据就从 Action 传到了 Dispatcher

Dispatcher

Dispatcher 的具体实现能够看 github.com/facebook/flux/blob/master/src/Dispatcher.js

游客只能够贴两个连接,我也是醉

当咱们用 Facebook 给咱们提供的 Dispatcher,那么一切都会变得简单了许多

npm install --save flux
import Flux from 'flux'; var Dispatcher = Flux.Dispatcher; export default new Dispatcher();

Dispatcher 在整个应用

只有一个,只有一个,只有一个

有人就说了,你 Dispatcher 只负责喊的,我不要你也好像能够呀。嗯嗯,那就不叫 Fulx 了,叫 Reflux github.com/spoike/refluxjs

Constants

刚刚咱们看到在咱们的 Actions 里,actionType: TodoConstants.TODO_CREATE,这个 TodoConstants 其实就是咱们操做的名字,至关于一个常量,定义在 Constants 里方便管理和调用而已。

通常你有多少个 action,就有多少个常量在这个 Constants 里

KeyMirror 就是建立一个对象,里面键的值等于键的名字 - -

Stores

主角登场! 但, Store 是什么?

Store 是一个保存数据的地方

var _todo = {};

Store 是一个充满逻辑的地方

全部 actions 的逻辑处理,都会在这里发生。像咱们的 create action

function create (text) { var id = (new Date() + Math.floor(Math.random() * 999999)).toString(36);
  _todos[id] = {
    id: id,
    complete: false,
    text: text
  };
}

Store 是一个响应 Dispatcher 呼喊的地方

“有人作了一个操做呀,这个操做就是 xxx (actionType 的值),还带了个参数,大家哪一个来处理一下呀”

在 Store 里,咱们经过 Dispatcher “注册”了一个回调函数,每当咱们调用 dispatch 函数的时候,就是 Dispatcher 大喊的时候,咱们根据不一样的 actionType,来调用咱们不一样的逻辑处理函数,像这样

import AppDispatcher from '../dispatcher/AppDispatcher'; import TodoConstants from '../constants/TodoConstants';

AppDispatcher.register((action) => { var text; switch(action.actionType) { case TodoConstants.TODO_CREATE:
      text = action.text.trim(); if (text !== '') {
        create(text);
        TodoStore.emitChange();
      } break; // other case }
});

Store 是一个鞭策 Controller View 改变的地方

每当 Store 改变了数据以后,他都要 Controller View 跟着他改变。他们还约定了暗号

var CHANGE_EVENT = 'change';

Store 跟 Controller View 说,我一喊 “变”,你听到以后,你就叫你的手下一块儿变。

Controller View 说好。

可是 Store 不会喊,Controller View 也听不到。

因此 Store 从 EventEmitter中学会了喊,也给 Controller View 买来了助听器

import assign from 'object-assign'; var EventEmitter = require('events').EventEmitter; var TodoStore = assign({}, EventEmitter.prototype, {
  areAllComplete () { for (var id in _todos) { if (!_todos[id].complete) { return false;
      }
    } return true;
  },
  getAll () { return _todos;
  },
  emitChange () { this.emit(CHANGE_EVENT);
  },
  addChangeListener (callback) { this.on(CHANGE_EVENT, callback);
  },
  removeChangeListener (callback) { this.removeListener(CHANGE_EVENT, callback);
  }
}); export default TodoStore;

因此每当执行完逻辑处理函数以后,Store 都会喊一句 TodoStore.emitChange();

助听器 addChangeListener (callback) { this.on(CHANGE_EVENT, callback) } 也买好了,成不成功,就看 Controller View 了

Controller View

在 Components 里,你看不到 TodoApp 这个组件,由于对于 Todo 这个 App,TodoApp 这个组件,就是 Contriller View,他掌管所有的 Components。

可是重要的是,他怎么带 Store 给他买的助听器

componentDidMount () {
  TodoStore.addChangeListener(this._onChange.bind(this));
}

当组件渲染完成后,就绑定了 Store 的 addChangeListener,并回调了本身的 onChange 方法。

_onChange () { this.setState(this.getTodoState.bind(this)());
}

Store 一喊,Controller View 听到以后,更新全部数据,以 props 的方式传给他的手下 - 即他掌管的 Components

Summary

如今咱们来疏理一下整个流程(就 create 而言)

  1. 用户输入要新增的 todo,一敲回车,触发 onKeydown 方法。
  2. onKeydown 调用了 onSave 方法,onSave 调用了 TodoActions.create 方法。
  3. TodoActions.create 触发了 AppDispatcher.dispatch 方法,AppDispatcher 大喊了一声。
  4. TodoStore 响应,根据 actionType 调用了 create 逻辑处理函数,执行完,喊了一句 “变”。
  5. Controller View 带着助听器听到了接着更新数据,把数据传给了各个 Components。
  6. 从新渲染,新增完毕。

以上是本人浅显的理解,若有错误,欢迎指正 : )

相关文章
相关标签/搜索