簡談flux

Flux前端

 

耍瞭解 Redux,首先要從 Flux 提及,能夠認爲 Redux 是 Flux 思想的另 一 種實現方 式,經過了解 Flux,咱們能夠知道 Flux一族框架(其中就包括 Redux)貫徹的最重要的 觀點一一單向數據流,更重要的是,咱們能夠發現 Flux框架的缺點,從而深入地認識到 Redux 相對於 Flux 的改進之處 。讓咱們來看看 Flux 的歷史,實際上, Flux是和React 同時面世的,在 2013 年, Face­book公司讓 React亮相的同時,也推出了 Flux框架, React和 Flux相輔相成, Facebook認爲二者結合在一塊兒才能構建大型的 JavaScript應用 。作 一 個容易理解的對比, React是用來替換 jQuery 的,那麼 Flux 就是以替換Backbone.js、 Ember.js 等 MVC 一族框架爲目的 。mvc

在 MVC ( Model-View-Controller)的世界裏, React至關於 v (也就是 View)的部分,只涉及頁面的渲染一旦涉及應用的數據管理部分,仍是交給 Model 和 Controller,不過,Flux並非 一 個 MVC 框架,事實上, Flux認爲 MVC 框架存在很大問題,它推翻了MVC 框架, 並用一個新的思惟來管理數據流轉 。框架

首先先說一下什麼是mvc框架函數

MVC 框架是業界普遍接受的一種前端應用框架類型,這種框架把應用分爲三個部分:this

model(模型) 負責管理數據,大部分業務邏輯也應該放在model中編碼

view(視圖)負責渲染用戶界面,應該避免view中涉及業務邏輯spa

controller(控制器)負責接受用戶的輸入,根據用戶的輸入調用對應的model部分邏輯,把產生的數據結果交給view部分,讓view渲染出必要的輸出prototype

關係圖以下debug

對於 MVC 框架,爲了讓數據流可控, Controller應該是中心,當 View 要傳遞消息 給 Model 時,應該調用 Controller 的方法,一樣,當 Model 要更新 View 時,也應該經過 Controller 引起新的渲染 。日誌

當Facebook推出Flux時,招致了不少質疑。 不少人都說, Flux只不過是一個對數 據流管理更加嚴格的 MVC 框架而已 。 這種說法不徹底準確,可是 必定意義上也說明了 Flux 的一個特色:更嚴格的數據流控制 。

Facebook 已經無意在 MVC 框架上糾纏,他們用 Flux 框架來代替原有的 MVC 框架,他們提出的 Flux 框架大體結構是圖 3-3 的模樣 。 

 

一個 Flux 應用包含四個部分,咱們先粗略瞭解一下:

Dispatcher,處理動做分發,維持 Store 之間的依賴關係; 

Store,負責存儲數據和處理數據相關邏輯 ;

Action,驅動 Dispatcher 的 JavaScript 對象

View,視圖部分,負責顯示用戶界面。 

若是非要把 Flux 和 MVC 作一個結構對比,那麼, Flux 的 Dispatcher至關於 MVC 的 Controller, Flux 的 Store至關於 MVC 的 Model, Flux 的 View 固然就對應 MVC 的 View 了,至於多出來的這個 Action,能夠理解爲對應給 MVC 框架的用戶請求 。

在 MVC 框架中,系統可以提供什麼樣的服務,經過 Controller暴露函數來實現 。 每增長 一個功能, Controller每每就要增長一個函數;在 Flux 的世界裏,新增長功能 並不須要 Dispatcher增長新的函數,實際上, Dispatcher 自始至終只須要暴露一個函數 Dispatch, 當須要增長新的功能時,要作的是增長一種新的 Action類型, Dispatcher 的對 外接口並不用改變 。

當須要擴充應用所能處理的「請求」時, MVC 方法就須要增長新的 Controller,而 對於 Flux 則只是增長新的 Action。 

1. Dispatcher

首先,咱們要創造一個 Dispatcher,幾乎全部應用都只須要擁有 一 個 Dispatcher, 對於咱們這個簡單的應用更不例外 。 在 src/AppDispatcher. 中,咱們創造這個惟 一 的 Dispatcher 對象,代碼以下: 

import {Dispatcher} from 'flux';

export default new Dispatcher();

很是簡單,咱們引人 flux庫中的 Dispatcher類,而後創造一個新的對象做爲這個文 件的默認輸出就足夠了 。 在其餘代碼中,將會引用這個全局惟一的 Dispatcher對象。

Dispatcher存在的做用,就是用來派發 action,接下來咱們就來定義應用中涉及的 action。 

 

2. action

ction顧名思義表明一個「動做」,不過這個動做只是一個普通的 JavaScript對象,代

表一個動做的純數據,相似於 DOMAPI 中的事件( event)。 甚至,和事件相比, action 其實仍是更加純粹的數據對象,由於事件每每還包含 一些方法,好比點擊事件就有 preventDefault方法,可是 action對象不自帶方法,就是純粹的數據。

做爲管理, action 對象必須有一個名爲 type 的字段,表明這個 action 對象的類型,

爲了記錄日誌和 debug 方便,這個 type 應該是字符串類型 。
定義 action 一般須要兩個文件,一個定義 action 的類型,一個定義 action 的構造函

數(也稱爲 action creator)。 分紅兩個文件的主要緣由是在 Store 中會根據 action 類型作 不一樣操做,也就有單獨導人 action類型的須要 。

在 src/ActionTypes.js 中,咱們定義 action 的類型,代碼以下:

export const INCREMENT = 'increment';

export const DECREMENT = 'decrement';

  

在這個例子中,用戶只能作兩個動做,一個是點擊「+」按鈕, 一個是點擊 鈕,因此咱們只有兩個 action類型則CREMENT 和 DECREMENT。

如今咱們在 src/Actions. 文件中定義 action 構造函數:

import * as ActionTypes from './ActionTypes.js';
import AppDispatcher from './AppDispatcher.js';

export const increment = (counterCaption) => {
  AppDispatcher.dispatch({
    type: ActionTypes.INCREMENT,
    counterCaption: counterCaption
  });
};

export const decrement = (counterCaption) => {
  AppDispatcher.dispatch({
    type: ActionTypes.DECREMENT,
    counterCaption: counterCaption
  });
};

  

雖然出於業界習慣,這個文件被命名爲 Actions.js,可是要注意裏面定義的並非action對象自己,而是可以產生並派發 action對象的函數。

在 Actions. 文件中,引入了 ActionTypes 和 AppDispatcher, 看得出來是要直接使用Dispatcher。

這個 Actions. 導出了兩個 action構造函數 increment和 decrement,當這兩個函數被調用的時候,創造了對應的 action對象,並當即經過 AppDispatcher.dispatch 函數派發出去 。 派發出去的 action對象最後怎麼樣了呢?在下面關於 Store 的部分能夠看到 。

 

3. Store

一個 Store也是一個對象,這個對象存儲應用狀態,同時還要接受 Dispatcher派發的 動做,根據動做來決定是否要更新應用狀態 。

接下來咱們創造 Store相關的代碼,由於使用 Flux以後代碼文件數量會增多,再把 全部源代碼文件都放在 src 目錄下就不容易管理了 。 因此咱們在 src 下建立一個子目錄 stores,在這個子目錄裏面放置全部的 Store代碼。

在前面demo的 Contro!Panel應用例子裏,有三個 Counter組件,還有一個統計三個 Counter 計數值之和的功能,咱們遇到的麻煩就是這二者之間的狀態如何同步的問題,如今,咱們創造兩個 Store,一個是爲 Counter組件服務的 CounterStore,另 一個就是爲總 數服務的 SummaryStore。

咱們首先添加 CounterStore,放在 src/stores/Count巳rStore. 文件中 。

const counterValues = {
  'First': 0,
  'Second': 10,
  'Third': 30
};


const CounterStore = Object.assign({}, EventEmitter.prototype, {
  getCounterValues: function() {
    return counterValues;
  },

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  }

});

  

當 Store 的狀態發生變化的時候, 須要通知應用的其餘部分作必要的響應 。 在咱們 的應用中,作出響應的部分固然就是 View部分,可是咱們不該該硬編碼這種聯繫,應 該用消息的方式創建 Store 和 View 的聯繫 。 這就是爲何咱們讓 CounterStore 擴展了 EventEmitter.prototype,等於讓 CounterStore成了 EventEmitter對象, 一個 EventEmitter 實例對象支持下列相關函數 。

1,emit 函數,能夠廣播一個特定事件,第一個參數是字符串類型的事件名稱 ;

2,on 函數,能夠增長一個掛在這個 EventEmitter對象特定事件上的處理函數,第一個參數是字符串類型 的事件名稱,第二個參數是處理函數;

3,removeListener 函數, 和 on 函數作的 事情相反, 刪 除掛在這個 EventEmitter對象特定事件上的處理函數,和 on 函數同樣, 第一個參數是事件名稱 ,第二個參數 是處理函數。 要注意, 若是要調用 removeListener函數, 就必定要保留對處理函 數的引用。

對於 CounterStore對象, emitChange、 addChangeListener和 removeChangeListener函 數就是利用 EventEmitter上述的三個函數完成對 CounterStore狀態更新的廣播 、添加監昕 函數和刪 除監昕 函數等操做 。

CounterStore 函數還提供一個 getCounterValues 函數,用於讓應用中其餘模塊能夠讀 取當前的計數值,當前的計數值存儲在文件模塊級的變量 counterValues 中

上面實現的 Store 只有註冊到 Dispatcher實例上才能真正發揮做用,因此還須要增長 下列代碼:

import AppDispatcher from '../AppDispatcher.js';
CounterStore.dispatchToken = AppDispatcher.register((action) => {
  if (action.type === ActionTypes.INCREMENT) {
    counterValues[action.counterCaption] ++;
    CounterStore.emitChange();
  } else if (action.type === ActionTypes.DECREMENT) {
    counterValues[action.counterCaption] --;
    CounterStore.emitChange();
  }
});
相關文章
相關標籤/搜索