React native 專案進階(redux, redux saga, redux logger)

wutongke發表於2017-03-04

之前利用知乎日報的api寫了react-native的一個入門專案,傳送文章地址React Native 專案入門和原始碼地址RN入門專案原始碼,目前github上的程式碼已經在原文的基礎上增加了新的功能,也就是本文進階的內容,看完本文感興趣的同學可以參考一下。

思考

在入門專案中我們已經實踐了React native 的基本用法,展示了知乎日報的列表和詳情頁。在小型的專案中這樣實踐當然是沒有問題的,我們在每個頁面中自行請求網路,渲染元件,完全可以。但是當專案變得複雜,需要增加新的feather或者擴充套件log日誌等基礎模組時,這樣的實踐絕對讓人苦不堪言,事倍功半。

從維護和功能擴充套件等角度來說,專案使用合適的框架是必需的。我們從日誌入手來分析,比如我們需要記錄系統中所有訪問網路的日誌,如果每個頁面中使用fetch訪問網路,則log需要記錄在每個頁面中進行記錄:

React native 專案進階(redux, redux saga, redux logger)
1.png

一種進階的方法是封裝網路請求方法,日誌記錄統一封裝模組中進行設定:
React native 專案進階(redux, redux saga, redux logger)
2.png

這種方法已經可以應付大部分情況,當log需求更改時,只需跟新一個模組即可。

如果這時需要增加資料庫訪問的日誌,我們按照相同的思路,可以定義一個資料庫訪問的模組,在該模組中定義相應的日誌模組。如果需要增加更多型別的日誌模組呢,是繼續按照同樣的思路繼續嗎?

我們看一下剛提到的兩種日誌,提取一下共同點,都需要記錄日誌,我們有沒有可能提取一個日誌模組,圖示一下思路:

React native 專案進階(redux, redux saga, redux logger)
3.png

假如這時又有一個需求是記錄一下所有操作的執行時間,並根據執行時間的統計對相應的系統引數進行調整,這時候怎麼解決呢,圖示思路,我們可以在中間繼續增加一個模組:

React native 專案進階(redux, redux saga, redux logger)
4.png

以上均是一些簡單的思路,在具體工程實踐中應該怎麼做呢?我們先來看一下Flux的思路。

Flux

React native 專案進階(redux, redux saga, redux logger)
5.png

我們先來看一下Flux中的幾個角色:

  • View: 檢視層
  • Action(動作):檢視層發出的訊息(比如mouseClick)
  • Dispatcher(派發器):用來接收Actions、執行回撥函式
  • Store(資料層):用來存放應用的狀態,一旦發生變動,就提醒Views要更新頁面

其基本思路是對所有的動作進行封裝,然後使用dispatcher對動作進行分發,在Store中完成處理後傳遞給View,完成一次完整資料流動,此流動為單向,不可逆。
其中Action我們理解為動作,此動作不僅包括動作型別(即目標,記錄日誌還是計算任務執行時間),同時還可以攜帶一定的資料,參照以上我們的思路圖4,非常符合我們的需求。

Redux

Redux 實際是flux思路的一種實現,在角色定義方面略有不同,但是不妨礙思路相同。

  • Action(動作) 與flux中的定義類似
  • reducer 對Action中定義是state進行更新,注意流程中只能通過reduce進行更新,同時reducer要保證為純函式,即對於一定對輸入,一定可以獲得相應的輸出,而不會受到時間或者因此的影響。
  • store store 實際完成了dispatcher的功能,同時連線了其他功能模組。

    維持應用的 state;
    提供 getState() 方法獲取 state;
    提供 dispatch(action) 方法更新 state;
    通過 subscribe(listener) 註冊監聽器;
    通過 subscribe(listener) 返回的函式登出監聽器。

redux還有一個重要的概念:中介軟體,中介軟體可以在資料傳遞過程中進行一些額外的動作,如上文提到的日誌記錄等功能。至此,我們可以利用redux完成我們需要的功能。本文主要介紹思路,關於redux的具體學習推薦阮一峰老師的部落格,Redux 入門教程

redux-saga

我們知道在應用中一定會有很多非同步操作,如網路訪問、資料讀取等,redux完成了資料的傳遞,但是在非同步操作部分如果我們不加註意,可能會寫出一團糟的程式碼,redux-saga正完成了這件事情。

Sagas 負責協調那些複雜或非同步的操作。

專案實踐

本文的專案進階就是在程式碼中加入對redux的支援,當然按照本專案的需求增加這些是沒有必要的,只是徒增了專案的複雜度。這裡主要演示redux以及中介軟體redux-saga, redux-logger在專案中的使用。其中saga在以上已經進行了介紹,redux logger 實際是對所有Action state 進行了紀錄,進行專案debug時,我們可以根據console的log輸出判斷專案的具體state變化:

React native 專案進階(redux, redux saga, redux logger)
Paste_Image.png

  • store 的建立
const middlewares = [];
// 建立reducer
const rootReducer = combineReducers({story});
// 建立中介軟體saga
const sagaMiddleware = saga();

middlewares.push(sagaMiddleware)
if (process.env.NODE_ENV === 'development') {
    //建立中介軟體logger
    const logger = createLogger();
    middlewares.push(logger);
}
//applymiddleware配置中介軟體
const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore);

function createDefaultStore(initialsState) {
    //通過reducer 獲取stare
    const defaultStore = createStoreWithMiddleware(rootReducer, initialsState);
    return defaultStore;
}
const store = createDefaultStore();複製程式碼
  • Reducers的建立
    可以建立多個reducers,通過

    combineReducers();複製程式碼

    進行組合

    const initialState = {
      id: "",
      refreshing: true,
      loaded: false,
      story: new Object()
    };
    export default function story(state = initialState, action) {
      switch (action.type) {
          case ActionType.Fetch_Story_Detail:
              return Object.assign({}, state, {
                  id: action.id,
                  refreshing: true,
                  loaded: false
              });
          case ActionType.Fetch_Story_Detail_Done:
              return Object.assign({}, state, {
                  id: action.id,
                  refreshing: false,
                  load: true,
                  story: action.story
              });
          default:
              return state;
      }
    }複製程式碼

    如上建立store reducer

  • connect
    介面元件需要connect redux,可以dispatch Actions,同時可以接收到相應的回撥,完成介面的render。

    function mapStateToProps(state) {
      const {story} = state;
      return {
          story
      };
    }
    StoryDetailPage.propTypes = propTypes;
    export default connect(mapStateToProps)(StoryDetailPage);複製程式碼

    經過這幾步,我們專案的結構就非常清晰了,在進行模組維護和擴充套件時就很方便了。

程式碼地址:react-native-zhihu

歡迎關注公眾號wutongke,每天推送移動開發前沿技術文章:

React native 專案進階(redux, redux saga, redux logger)
wutongke

推薦閱讀:

React-native專案入門與思考
React native 專案入門(知乎日報,豆瓣電影,[one]一個)
React native 專案進階(redux, redux saga, redux logger)

React Native 專案2(One 【一個】客戶端)

感謝:
www.ruanyifeng.com/blog/2016/0…
www.ruanyifeng.com/blog/2016/0…
github.com/kenberkeley…
leonshi.com/redux-saga-…
cn.redux.js.org/index.html

相關文章