從零開始的 Android新專案(10 ): React Native & Redux

markzhai發表於2016-08-23

本系列:


本篇來講講 React Native 和 Redux,和其他一上來就啪啪啪丟上來一堆翻譯的東西不同,本文會從簡單的例子入手,讓大家能快速地明白 React Native 是什麼,Redux 和常見的 MVC、MVP 等有什麼區別,怎麼去組織一個 Redux 架構的 React Native 專案。

為避免大家還沒入門就放棄,預計下一篇才會從我們專案中的實踐出發,講講更復雜的應用場景。

什麼是React Native

React Native

React Native

React Native 使你能夠基於 JavaScript 和 React 在原生平臺上構建應用,提倡的是 “learn once, write anywhere”,複用程式碼,提高開發效率。

專案由 Facebook 開源驅動,在過去的近一年中更新很活躍。文件建議直接看官網的 React Native,中文站有點坑。

支援系統:Android 4.1 (API 16) 以及 >= iOS 7.0。

關於 React,可以參見之前為掘金翻譯計劃翻譯的 React.js 新手村教程,簡單來說 React 將應用分為一個個動態可複用的元件 —— View的渲染(JSX)、資料如何繫結到顯示、狀態的變更(State)、屬性(Props)都包含在元件內部。

React.js

React.js

整個應用由一個個元件搭積木而成(元件式開發),而每個元件則由狀態驅動而變更。

React Native 正像它的名字,將 React 帶到了原生世界,和 H5 不同的是,我們不再使用 CSS 和 HTML,而只有 js 為伴。我們也不再有那些 div, input 這些標籤,而是由 View, TextInput 等等取代,更符合原生開發者們的習慣。佈局上,幸而有強大的 Flexbox 支援,如果開發者們之前有使用或者看到過 Google 在 GitHub 釋出的 Android 版 FlexboxLayout,相信對它會很熟悉。原生開發中的頁面棧,也由 Navigator 進行了實現(在 Android 上還有 BackAndroid 的返回鍵支援)。

與 WebView 不同,React Native 執行的介面,最終會被解釋對映為原生的 View,可以直接使用佈局邊界或者 Hierarchy Viewer 看出層級(js 檔案會打包為一個bundle,位於assets下面,RN引擎會載入並進行解釋對映)。

好處

  • 體驗 web 開發的便捷,不再需要編譯,重新載入一下 js 就行了
  • 可以直接使用 Chrome 或者 Nuclide 除錯
  • Android / iOS 兩端可以共享很大一部分程式碼(RN 還在進行 Windows, MacOS, Node-webkit 等平臺的支援)
  • 熱更新,JS bundle 下發一下新的就行了(當然也有一定侷限性,如果是 hybrid,則 native 的 RN module 部分不能更新)

壞處

  • 前端開發不會原生做不了 React Native(除非你能真只用自帶的那些東西),而且理解那些 RN 提供的元件也會很頭暈(需要同時瞭解 Android 和 iOS)。
  • 原生開發需要一定成本的學習實踐才能掌握 React Native。畢竟 ES6 不像過去的 JS 那麼傻瓜式了。
  • React Native 目前仍然處於快速迭代開發的階段,你永遠也不知道下個版本自己升級需要修改多少原來的程式碼。
  • React Native 的資料較少,尤其是國內的,更尤其是 hybrid 開發的(GitHub 上的開源專案大多是純 RN 的)。

什麼是Redux

Redux.js

Redux.js

Redux 本身和 React 並沒有特別緊密的聯絡,而是 Facebook 提出的 Flux 架構的一種優秀實現,可以搭配其他任何框架一起使用。在 React 上使用,需要搭配 react-redux(如此一來 Redux 可以不侷限於 React,而讓社群發展出更多的 redux-* 中介軟體)。

Redux 在 React 的基礎上(state 和 props),增加了 storeactionreducer 的概念,規範了全域性一個 state,從而只需要根據這個 state 就能回朔出整個應用的狀態。元件通過 dispatch 將 action 傳到 store,reducer 根據原來的 state 以及 action,返回新的 state,元件根據新的 state 渲染介面。

Redux 是一個可預測的狀態容器,即只需要有狀態樹,就能還原出“事發現場”。

從例子看專案

為了避免說一大堆概念,大家一頭霧水,似懂非懂,這裡拿一個例子來講講 React Native 和 Redux 結合後的效果,儘量避免程式碼的出現,而以圖和文字代替。

Counter!沒錯,就是 Counter,不是 TODO,TODO已經被黑的不成樣了。

專案原始碼位於:example-react-native-redux。包含了 CounterCounters 兩個子專案。前者是單個的計數器,後者則在前者的基礎上增加了可以加減計數器個數的功能,相對更復雜一些,不過引入了一些不錯的實踐可以參考。

執行效果

先看看最後的效果,方便對應後面的解說。
第一個 Counter 專案很簡單,就是一個文字框加上兩個按鈕,一個加1,一個減1。
第二個 Counters 專案在前者的基礎上(使用了 Counter 元件),可以增加任意個計數器,還新增了帶延遲的加1功能,來模擬耗時操作。

Counter

先看看Counter,我們從物理架構和動作流兩個角度來進行觀察。

目錄下,有以下檔案:

Counter List Files

Counter List Files

index.android.js 和 index.ios.js 分別是 android 和 iOS 的 rn 入口,通常內容是相同的。
android 為 Android 的工程目錄,下面有我們熟悉的 build.gralde。
ios 為 iOS 的工程目錄,包含了 xcode 的專案。
app 就是 rn 的目錄,包含了 Android 和 iOS 專案共享的 js 原始碼。
node_modules 是 node 通過解析 package.json 下載的依賴。

物理結構

Counter物理結構

Counter物理結構

CounterApp.js 則是整個應用的實際入口。

動作流

且不談那些具體的 bind 和 createStore 操作,我們來看看當發生互動的時候,整個動作的分發,拿點選加號為例:

Counter活動圖

Counter活動圖

onPress 事件觸發了後續的一系列活動,而 Counter Component 的 action function 則由外部通過 props 傳入(在這裡,是 CounterApp 的 render 函式,如下)。

counterApp.js

counterApp.js

再看看 store 的建立,在 App.js 入口:

app.js

app.js

而 Component 也不是直接呼叫 action 的 function,而是通過 bindActionCreators 注入到元件props中(這裡是通過 react-redux 進行的,不是 redux 自身的東西,可以理解為 react 和 redux 之間的膠水):

action bind

action bind

通常我們會在智慧元件的末尾使用:

這樣來把 state 以及 action 注入。

Counters

接著我們來看看更為複雜的 Counters 專案,頂層目錄結構類似,不再贅述。

demo

demo

看完上面的 demo 動圖後,相信大家對下面的解說會更容易理解。

物理結構

Counters物理結構

Counters物理結構

我們來詳細講一下 modules 下的 app 目錄中的檔案組織。

actions.js 和剛才一樣,定義了一個個的 action,略有不同的是由於這次有非同步的操作,所以涉及到了 dispatch 函式,關於 dispatch 可以檢視官方文件

constants.js 定義了所有 action 的 type,以及 App 的名字。

reducers.js 一樣根據 action(payload 和 type)以及原來的 state 返回新的 state,另外,這裡還進行了 initial state 即初始狀態的定義(我們也可以把它放到單獨的檔案中)。

App.js 定義了頁面的佈局(渲染和 action),匯出了 connect 生成的 container。我們簡單看一下 render 部分是怎麼做的。

Counters render

Counters render

怎麼樣,JSX 是不是挺容易理解的?

動作流

Counter 本身的動作流上面我們已經舉例過了,本工程中增減計數類似,唯一的區別是 action 不只有 type,還帶了 payload(id)來標示不同的計數器。

所以這裡我們拿增加計數器的點選事件來做例子。

Add Counter

Add Counter

看上去是不是跟上面的差不多?剩下的那個 incrementWithDelay 其實也差不多,只不過返回的是一個function,在 setTimeOut 回撥中才進行 dispatch(thunk middleware 會幫我們進行處理)。

總結

上面我們通過物理結構和活動圖大致瞭解了 React Native 上的 Redux 架構 app 是如何工作的。具體的細節,建議大家還是去檢視 GitHub 上的原始碼,通過上面的講解後,應該不難理解。

技術棧

我們目前實踐的React Nataive技術棧:

  • immutable.js
  • react
  • redux
  • react-redux
  • redux-thunk
  • redux-logger
  • redux-mock-store
  • react-native-router-flux
  • react-native-simple-store
  • regenerator
  • undefined
  • jest

更多閱讀

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

從零開始的 Android新專案(10 ): React Native & Redux 從零開始的 Android新專案(10 ): React Native & Redux

相關文章