學習 React.js:瞭解 Flux,React.js 的架構
Getting To Know Flux,the React.js Architecture Ken Wheeler (@ken_wheeler) #簡介 歡迎來到學習 React 的第三章。今天我們將會學習臉書的 Flux 架構的工作方式,以及我們怎麼把它應該用到我們的工程中。 如果你沒有準備好,我強烈建議你回去看看這個系列的第一、第二章,Getting Started & Concepts 和 Building a Real Time Twitter Stream with Node and React。當然我不強迫你們,不過如果你不熟悉 React.js 的化,這兩篇文章肯定對你很有用。 ##什麼是 Flux? Flux 是臉書內部用來配合 React 工作的一個架構。它不是框架或者庫。它只是一個配合 React 的新的體系結構,以及單向數據流的概念。 也就是說,臉書提供了了一個包含了 Dispatcher 庫的 repo。這個庫是用來專門處理那些全局的,廣播消息到註冊事件上的發佈/訂閱模式的。 一個典型的 Flux 架構用例是,配合 NodeJS 的 EventEmitter 模塊來創建一個事件系統,用於管理應用的狀態。 解釋 Flux 的最好方式我想應該就是把它的組件給挨個介紹一下:
讓我們來看看示意圖: API 是幹嘛的? 當你需要用到從外面(或者發送出去)的數據的時候,我發現用 Actions 引入數據到 Flux 流,然後傳給 Stores,是最無痛的方式。 #Dispatcher 那 Dispatcher 到底是什麼? Dispatcher 是管理整個流程的基礎。它是你的應用的樞紐核心。dispatcher 接收 actions ,然後把 actions 和數據推送給註冊的囘調。 那本質就是 發佈/訂閱 咯? 也不完全就是這樣。despatcher 廣播負載給所有的註冊囘調,並且可以允許你按照一定順序來調用囘調,甚至還可以在執行之前做暫停等待更新。在你的應用中,只有一個 despatcher,它的職責就是扮演你的核心樞紐。 看起來應該像這樣: <!-- lang: js --> var Dispatcher = require('flux').Dispatcher; var AppDispatcher = new Dispatcher(); AppDispatcher.handleViewAction = function(action) { this.dispatch({ source: 'VIEW_ACTION',action: action }); } module.exports = AppDispatcher; 上面的例子中,我們創建了一個 Dispatcher 的實例並且創建了一個 我們的方法調用dispatch 方法,它會廣播 用圖來描述看起來應該是這樣: Dispatcher 模塊有一個很酷的功能,就是可以在 Stores 中定義依賴和管理囘調。所以如果你的應用中某一部分的更新,需要另一部分先更新的話,Dispatcher 的 為了用這個功能,我們需要在 Store 裏面保存 Dispatcher 註冊方法的返回值,以 <!-- lang: js --> ShoeStore.dispatcherIndex = AppDispatcher.register(function(payload) { }); 然後在我們的 Store 中,當我們要處理某個動作時,我們可以用 Dispatcher 的 <!-- lang: js --> case 'BUY_SHOES': AppDispatcher.waitFor([ ShoeStore.dispatcherIndex ],function() { CheckoutStore.purchaseShoes(ShoeStore.getSelectedShoes()); }); break; #Stores 在 Flux 中,Stores 管理著你的應用中特殊部分的 state。或者通俗點講,包括有應用的每個部分,保存管理數據,數據查詢和調用囘調之類。 我們來看一個最基本的 Store: <!-- lang: js --> var AppDispatcher = require('../dispatcher/AppDispatcher'); var ShoeConstants = require('../constants/ShoeConstants'); var EventEmitter = require('events').EventEmitter; var merge = require('react/lib/merge'); // Internal object of shoes var _shoes = {}; // Method to load shoes from action data function loadShoes(data) { _shoes = data.shoes; } // Merge our store with Node's Event Emitter var ShoeStore = merge(EventEmitter.prototype,{ // Returns all shoes getShoes: function() { return _shoes; },emitChange: function() { this.emit('change'); },addChangeListener: function(callback) { this.on('change',callback); },removeChangeListener: function(callback) { this.removeListener('change',callback); } }); // Register dispatcher callback AppDispatcher.register(function(payload) { var action = payload.action; var text; // Define what to do for certain actions switch(action.actionType) { case ShoeConstants.LOAD_SHOES: // Call internal method based upon dispatched action loadShoes(action.data); break; default: return true; } // If action was acted upon,emit change event ShoeStore.emitChange(); return true; }); module.exports = ShoeStore; 上面的代碼中我們做的最重要的事情就是把我們的 store 用 NodeJS 的 EventEmitter 擴展了。這允許我們的 store 來監聽/廣播 事件。允許我們的 視圖/組件 基於這些事件來更新。因為我們的 Controller View 監聽著 Store,利用這些事件的變化,可以讓 Controller View 知道我們的應用 state 是否發生變化,以及是否應該刷新來保持顯示一致。 我們還用它的 我們的 public 方法 #Action Creator 和 Actions 動作創建者是動作集合,用來在 View (或者要幹事的任何地方),用來把發送給 Dispatcher 的。動作會被通過 dispatcher 推送。 臉書是這樣用它的,action 的類型常量用來決定應該觸發何種 action,應該配合何種 action 數據。在註冊囘調中,這些動作可以通過動作類型來處理,並且可以作為參數,配合動作數據來調用這些動作。 來看看常量的定義: <!-- lang: js --> var keyMirror = require('react/lib/keyMirror'); module.exports = keyMirror({ LOAD_SHOES: null }); 上面我們用了 React 的 現在來看看對應的 Action Creator 的定義: <!-- lang: js --> var AppDispatcher = require('../dispatcher/AppDispatcher'); var ShoeStoreConstants = require('../constants/ShoeStoreConstants'); var ShoeStoreActions = { loadShoes: function(data) { AppDispatcher.handleAction({ actionType: ShoeStoreConstants.LOAD_SHOES,data: data }) } }; module.exports = ShoeStoreActions; 在我們上面的例子中,我們在 #Controller Views Controller Views 沒什麽好說,它們就是 React 組件,用來監聽變更事件,然後處理從 Stores 過來的應用狀態的。它們會通過 props 把數據傳播下去給子組件。 看起來應該像這樣: <!-- lang: js --> /** @jsx React.DOM */ var React = require('react'); var ShoesStore = require('../stores/ShoeStore'); // Method to retrieve application state from store function getAppState() { return { shoes: ShoeStore.getShoes() }; } // Create our component class var ShoeStoreApp = React.createClass({ // Use getAppState method to set initial state getInitialState: function() { return getAppState(); },// Listen for changes componentDidMount: function() { ShoeStore.addChangeListener(this._onChange); },// Unbind change listener componentWillUnmount: function() { ShoesStore.removeChangeListener(this._onChange); },render: function() { return ( <ShoeStore shoes={this.state.shoes} /> ); },// Update view state when change event is received _onChange: function() { this.setState(getAppState()); } }); module.exports = ShoeStoreApp; 上面的例子中,我們通過 我們的應用狀態數據被保存在 Stores ,所以我們用 Stores 的 public 方法來接收和設置應用狀態。 #放一塊 現在我們把 Flux 架構的各部分獨立的過了一遍,我們應該比較好的理解了這個架構實際是怎樣工作的了。還記得我們之前看過的那個圖片麽?讓我們更深入的來看看它,現在我們明白了這個流程裏面的每一步是做什麼的了: #組裝 讀完這篇文章之後,我希望你如果之前沒有"認識"臉書的 Flux 架構的話,現在你可以說你知道了。只有實際用它來做些東西之後,你才會知道 React.js 是怎樣一回事。 當你用過 Flux 一次之後,不用 Flux 寫 React 的感覺就像操作 DOM 不用 jQuery 一樣抓狂。當然你也能做到,但是總覺得不優雅,不夠結構化。 如果你希望用 Flux 架構,不過你不想用 React,來看看 Delorean ,一個 Flux 框架,你可以用 Ractive.js 或者 Flight。還有另外一些值得看看的庫,比如說 Fluxxor,它提供了一種不同的 Flux 方式,以 Flux 實例為中心提供了一套緊耦合的 Flux 組件。 好了,我相信你已經真正的掌握了 Flux 了,你也實際有用到它了,所以我們在學習 React 的第四章將用 Reach.js 和 Flux 架構來創建一個購物車站點。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |