在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ Flux
React 組件
Redux 的基礎概念
JSX
DOM 操作
在 React 應用中使用 Redux
進化 Flux
Webpack 配置 React 開發(fā)環(huán)境
服務器端渲染
組合組件
表單
屬性擴散
開發(fā)環(huán)境配置
組件生命周期
Data Flow
JSX 與 HTML 的差異
組件間通信
使用 JSX
事件處理
Flux
React 概覽
Mixins
Redux

Flux

React 標榜自己是 MVC 里面 V 的部分,那么 Flux 就相當于添加 M 和 C 的部分。

Flux 是 Facebook 使用的一套前端應用的架構模式。

一個 Flux 應用主要包含四個部分:

  • the dispatcher

    處理動作分發(fā),維護 Store 之間的依賴關系

  • the stores

    數(shù)據(jù)和邏輯部分

  • the views

    React 組件,這一層可以看作 controller-views,作為視圖同時響應用戶交互

  • the actions

    提供給 dispatcher 傳遞數(shù)據(jù)給 store

針對上面提到的 Flux 這些概念,需要寫一個簡單的類庫來實現(xiàn)銜接這些功能,市面上有很多種實現(xiàn),這里討論 Facebook 官方的一個實現(xiàn) Dispatcher.js

單向數(shù)據(jù)流

先來了解一下 Flux 的核心“單向數(shù)據(jù)流“怎么運作的:

Action -> Dispatcher -> Store -> View

更多時候 View 會通過用戶交互觸發(fā) Action,所以一個簡單完整的數(shù)據(jù)流類似這樣:

http://wiki.jikexueyuan.com/project/react-tutorial/images/flux-overview.png" alt="flux overview" />

整個流程如下:

  • 首先要有 action,通過定義一些 action creator 方法根據(jù)需要創(chuàng)建 Action 提供給 dispatcher
  • View 層通過用戶交互(比如 onClick)會觸發(fā) Action
  • Dispatcher 會分發(fā)觸發(fā)的 Action 給所有注冊的 Store 的回調函數(shù)
  • Store 回調函數(shù)根據(jù)接收的 Action 更新自身數(shù)據(jù)之后會觸發(fā)一個 change 事件通知 View 數(shù)據(jù)更改了
  • View 會監(jiān)聽這個 change 事件,拿到對應的新數(shù)據(jù)并調用 setState 更新組件 UI

所有的狀態(tài)都由 Store 來維護,通過 Action 傳遞數(shù)據(jù),構成了如上所述的單向數(shù)據(jù)流循環(huán),所以應用中的各部分分工就相當明確,高度解耦了。

這種單向數(shù)據(jù)流使得整個系統(tǒng)都是透明可預測的。

Dispatcher

一個應用只需要一個 dispatcher 作為分發(fā)中心,管理所有數(shù)據(jù)流向,分發(fā)動作給 Store,沒有太多其他的邏輯(一些 action creator 方法也可以放到這里)。

Dispatcher 分發(fā)動作給 Store 注冊的回調函數(shù),這和一般的訂閱/發(fā)布模式不同的地方在于:

  • 回調函數(shù)不是訂閱到某一個特定的事件/頻道,每個動作會分發(fā)給所有注冊的回調函數(shù)
  • 回調函數(shù)可以指定在其他回調之后調用

基于 Flux 的架構思路,Dispatcher.js 提供的 API 很簡單:

  • register(function callback): string 注冊回調函數(shù),返回一個 token 供在 waitFor() 使用
  • unregister(string id): void 通過 token 移除回調
  • waitFor(array ids): void 在指定的回調函數(shù)執(zhí)行之后才執(zhí)行當前回調。這個方法只能在分發(fā)動作的回調函數(shù)中使用
  • dispatch(object payload): void 分發(fā)動作 payload 給所有注冊回調
  • isDispatching(): boolean 返回 Dispatcher 當前是否處在分發(fā)的狀態(tài)

dispatcher 只是一個粘合劑,剩余的 Store、View、Action 就需要按具體需求去實現(xiàn)了。

接下來結合 flux-todomvc 這個簡單的例子,提取其中的關鍵部分,看一下實際應用中如何銜接 Flux 整個流程,希望能對 Flux 各個部分有更直觀深入的理解。

Action

首先要創(chuàng)建動作,通過定義一些 action creator 方法來創(chuàng)建,這些方法用來暴露給外部調用,通過 dispatch 分發(fā)對應的動作,所以 action creator 也稱作 dispatcher helper methods 輔助 dipatcher 分發(fā)。 參見 actions/TodoActions.js

var AppDispatcher = require('../dispatcher/AppDispatcher');
var TodoConstants = require('../constants/TodoConstants');

var TodoActions = {
  create: function(text) {
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_CREATE,
      text: text
    });
  },

  updateText: function(id, text) {
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_UPDATE_TEXT,
      id: id,
      text: text
    });
  },

  // 不帶 payload 數(shù)據(jù)的動作
  toggleCompleteAll: function() {
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_TOGGLE_COMPLETE_ALL
    });
  }
};

AppDispatcher 直接繼承自 Dispatcher.js,在這個簡單的例子中沒有提供什么額外的功能。TodoConstants 定義了動作的類型名稱常量。

類似 create、updateText 就是 action creator,這兩個動作會通過 View 上的用戶交互觸發(fā)(比如輸入框)。 除了用戶交互會創(chuàng)建動作,服務端接口調用也可以用來創(chuàng)建動作,比如通過 Ajax 請求的一些初始數(shù)據(jù)也可以創(chuàng)建動作提供給 dispatcher,再分發(fā)給 store 使用這些初始數(shù)據(jù)。

action creators are nothing more than a call into the dispatcher.

可以看到所謂動作就是用來封裝傳遞數(shù)據(jù)的,動作只是一個簡單的對象,包含兩部分:payload(數(shù)據(jù))和 type(類型),type 是一個字符串常量,用來標識動作。

Store

Stores 包含應用的狀態(tài)和邏輯,不同的 Store 管理應用中不同部分的狀態(tài)。如 stores/TodoStore.js

var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var TodoConstants = require('../constants/TodoConstants');
var assign = require('object-assign');

var CHANGE_EVENT = 'change';

var _todos = {};

// 先定義一些數(shù)據(jù)處理方法
function create(text) {
  var id = (+new Date() + Math.floor(Math.random() * 999999)).toString(36);
  _todos[id] = {
    id: id,
    complete: false,
    text: text
  };
}
function update(id, updates) {
  _todos[id] = assign({}, _todos[id], updates);
}
// ...

var TodoStore = assign({}, EventEmitter.prototype, {
  // Getter 方法暴露給外部獲取 Store 數(shù)據(jù)
  getAll: function() {
    return _todos;
  },
  // 觸發(fā) change 事件
  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },
  // 提供給外部 View 綁定 change 事件
  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  }
});

// 注冊到 dispatcher,通過動作類型過濾處理當前 Store 關心的動作
AppDispatcher.register(function(action) {
  var text;

  switch(action.actionType) {
    case TodoConstants.TODO_CREATE:
      text = action.text.trim();
      if (text !== '') {
        create(text);
      }
      TodoStore.emitChange();
      break;

    case TodoConstants.TODO_UPDATE_TEXT:
      text = action.text.trim();
      if (text !== '') {
        update(action.id, {text: text});
      }
      TodoStore.emitChange();
      break;
  }
});

在 Store 注冊給 dispatcher 的回調函數(shù)中會接受到分發(fā)的 action,因為每個 action 都會分發(fā)給所有注冊的回調,所以回調函數(shù)里面要判斷這個 action 的 type 并調用相關的內部方法處理更新 action 帶過來的數(shù)據(jù)(payload),再通知 view 數(shù)據(jù)變更。

Store 里面不會暴露直接操作數(shù)據(jù)的方法給外部,暴露給外部調用的方法都是 Getter 方法,沒有 Setter 方法,唯一更新數(shù)據(jù)的手段就是通過在 dispatcher 注冊的回調函數(shù)。

View

View 就是 React 組件,從 Store 獲取狀態(tài)(數(shù)據(jù)),綁定 change 事件處理。如 components/TodoApp.react.js

var React = require('react');
var TodoStore = require('../stores/TodoStore');

function getTodoState() {
  return {
    allTodos: TodoStore.getAll(),
    areAllComplete: TodoStore.areAllComplete()
  };
}

var TodoApp = React.createClass({

  getInitialState: function() {
    return getTodoState();
  },

  componentDidMount: function() {
    TodoStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    TodoStore.removeChangeListener(this._onChange);
  },

  render: function() {
    return <div>/*...*/</div>
  },

  _onChange: function() {
    this.setState(getTodoState());
  }
});

一個 View 可能關聯(lián)多個 Store 來管理不同部分的狀態(tài),得益于 React 更新 View 如此簡單(setState),復雜的邏輯都被 Store 隔離了。

更多資料