Flux入門

這篇文章來自國外一位作者的Flux For Stupid People,文章沒有深究flux的具體實現(xiàn),但對于想入門flux的你會有所收獲。

我應該使用Flux么

  • 如果你的應用有很多動態(tài)數(shù)據(jù)需要處理,你可能需要flux。
  • 如果你的應用多包含靜態(tài)視圖,并且很少涉及到數(shù)據(jù)的存儲和更新,那么flux也許不會給你帶來任何好處。

什么是Flux

Flux通過事件和監(jiān)聽來實現(xiàn)了單向數(shù)據(jù)流,具體請看后文。
我們在示例代碼中使用了這兩個庫:Flux Dispatchermicroevent.js。

官方的文檔過于意識流,不適合新手學習。我們在學習時也不要將Flux與一些MVC框架相比,否則你會更加迷惑。

下面是一些Flux中提到的基本概念

1. Your Views "Dispatch" "Actions"(視圖觸發(fā)事件)

dispatcher 是一個基本的事件系統(tǒng),他有自己的一些規(guī)則。他會廣播事件,并注冊回調(diào)函數(shù)。這里我們有僅一個全局的dispatcher。你應該使用FB的Dispatcher Library。初始化很容易:

var AppDispatcher = new Dispatcher(); 

假設你有一個按鈕,點擊之后會向列表增加一條數(shù)據(jù)。

<button onClick={ this.createNewItem }>New Item</button> 

點擊之后,你的視圖會分發(fā)一個action,其中有action的名稱和增加的數(shù)據(jù)內(nèi)容:

createNewItem: function( evt ){
  AppDispatcher.dispatch({
      actionName: 'new-item', 
      newItem: { name: 'Marco' } // 所需要增加的一條數(shù)據(jù) 
  });
}

"action"是一個核心概念。他是一個js對象,描述了我們需要做的事和我們需要的數(shù)據(jù)。如上所述,我們要做的是添加一條數(shù)據(jù),我們需要的數(shù)據(jù)是一個名叫"Marco"的name。

Your "Store" Responds to Dispatched Actions(store觸發(fā)回調(diào))

store也是一個核心概念。我們在應用中創(chuàng)建一個集合,存放方法和數(shù)據(jù),它通常是一個列表。

store是單例的,在你的整個應用中只有一個store存在:

// Single object representing list data and logic
var ListStore = {  
// Actual collection of model data 
  items: []
};

store會對被分發(fā)的action做出處理:

var ListStore = ...

//在dispatcher中注冊我們需要監(jiān)聽的一些事件
AppDispatcher.register( function( payload ) {
    switch( payload.actionName ){
        //對action作出處理
        case 'new-item':
            //存儲一個數(shù)據(jù)
            ListStore.items.push( payload.newItem);
            break;
   }
});

以上是一個典型的例子,介紹了Flux處理回調(diào)函數(shù)的方式。傳入的參數(shù)payload包含了action的名稱和需要處理的數(shù)據(jù)。
switch語句中會對相應的action做出數(shù)據(jù)的處理。

關鍵概念:

  • store不是MVC中的model,但是它包含了models。
  • 應用中數(shù)據(jù)處理只能在store中進行,這是Flux核心理念。被分發(fā)的action無法增加或者刪除一條數(shù)據(jù)。

假設,你的應用中需要保存一些圖片及其基本信息,那么你應該再創(chuàng)建一個Items,命名為ImageItems。一個數(shù)組即可代表一種數(shù)據(jù)類型了。

只有stores能夠注冊被分發(fā)action的回調(diào)函數(shù)。千萬不要在視圖中調(diào)用AppDispatcher.register。dispatcher只會單向地從視圖傳遞數(shù)據(jù)給store。視圖會針對不同的事件重新渲染。

Your Store Emits a "Change" Event(store觸發(fā)change事件)

現(xiàn)在,store中的數(shù)據(jù)已經(jīng)改變了,我們傳遞出數(shù)據(jù)改變的信息了。

我們將讓store出發(fā)一個事件,如果在你使用了MicroEvent.js

MicroEvent.mixin( ListStore );

然后觸發(fā)change事件:

case 'new-item':
     ListStore.items.push( payload.newItem ); 
  
   // Tell the world we changed! 
     ListStore.trigger('change');
     break;

關鍵概念:

  • 事件觸發(fā)的時候不傳遞數(shù)據(jù),視圖只關心是否有數(shù)據(jù)發(fā)生變化。

Your View Responds to the "Change" Event(視圖接收到事件重新渲染)

視圖會在數(shù)據(jù)發(fā)生變化后重新渲染,沒錯是重新渲染。

我們在react組件的初始化完成后為store注冊監(jiān)聽:

componentDidMount: function( ) {
    ListStore.bind( 'change', this.listChanged );
},

為了簡單起見,我們調(diào)用forceUpdate,使視圖重新渲染。

listChanged : function() {
    this.forceUpdate( );
},

別忘記在組件回收時,解綁監(jiān)聽的事件:

componentWillUnmount: function( ){
      ListStore.unbind( 'change', this.listChanged );
},

然后來看下組件的render函數(shù):

render: function() {  
    // Remember, ListStore is global!  
    // There's no need to pass it around 
    var items = ListStore.getAll();  
    // Build list items markup by looping  
    // over the entire list 
    var itemHtml = items.map( function( listItem ) {  
      // "key" is important, should be a unique  
      // identifier for each list item 
        return <li key={ listItem.id }>
              { listItem.name }
                    </li>; 
      });
     return <div> 
                  <ul> { itemHtml } </ul> 
                  <button onClick={ this.createNewItem }>New Item</button> 
     </div>;
}

我們已經(jīng)完成了整個數(shù)據(jù),視圖更新過程.當你添加一條數(shù)據(jù)的時候,視圖會分發(fā)一個action,store會對action做出數(shù)據(jù)處理,并且觸發(fā)一個change事件,之后視圖接受到change事件并重新渲染。

但是有一個問題,每當數(shù)據(jù)更新的時候,視圖將全部重新渲染,這樣是否會造成效率低下?
其實并不會發(fā)生你所擔心的事情,React內(nèi)部構(gòu)建了虛擬DOM,react會比較視圖是否發(fā)生變化,實現(xiàn)部分的渲染,是以JS計算開銷換取了dom渲染開銷的方法來提升效率。

One More Thing: What The Hell Is An "Action Creator"?(Action Creator是什么鬼?)

我們在點擊按鈕的時候觸發(fā)了一個action

AppDispatcher.dispatch({
     eventName: 'new-item', 
     newItem: { name: 'Samantha' }
 });

當我們擁有很多按鈕,需要出發(fā)不同的action時,我們需要這么寫看起來會比較優(yōu)雅:

ListActions = { 
add: function( item ) { 
  AppDispatcher.dispatch({ 
      eventName: 'new-item', 
      newItem: item 
  }); 
}

del: ...

};

現(xiàn)在增加一條數(shù)據(jù)的時候就只需要這么寫:ListActions.add({ name: '...' })

PS:不要使用 forceUpdate

文中只為了簡單起見,使用了forceUpdate,正確的做法應該從store中讀取數(shù)據(jù),并且改變state,觸發(fā)視圖更新。

這里有一個demo,主要實現(xiàn)了一個簡單的Todo。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 去年翻譯的flux官方文檔對flux架構(gòu)的描述,覺得最近很多朋友開始react編程了,所以我覺得有必要拿出來這篇水...
    余歌_非魚閱讀 2,698評論 0 9
  • 原教程內(nèi)容詳見精益 React 學習指南,這只是我在學習過程中的一些閱讀筆記,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,940評論 1 18
  • 翻譯:莫銘原文地址:Flux-In Depth Overview Flux是Facebook用來構(gòu)建客戶端web應...
    莫銘閱讀 2,293評論 0 0
  • 莫名其妙的來到這個世界,緊接著你和某些人有了聯(lián)系,過了很多年,中間發(fā)生了很多事,最后她(他)們離開了你,莫名其妙的...
    b5ae43851ea6閱讀 263評論 0 1
  • 廣州剛又下了一場雨,雨后心情反而煩悶。
    話不多Mr閱讀 359評論 0 0

友情鏈接更多精彩內(nèi)容