【天贏金創】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. 從新渲染,新增完畢。

以上是本人淺顯的理解,若有錯誤,歡迎指正 : )

相關文章
相關標籤/搜索