基于 Redux 的 React Native 應用架構(1/2)

博客地址:http://davidleee.com
原文鏈接:http://davidleee.com/2017/04/20/Build-App-With-Redux/

自從 Facebook 把 React Native 給開源了之后,使用前端技術進行移動應用開發的趨勢已經越來越明顯,現在連微軟爸爸都用上了 React Native(ReactXP),我們還有什么理由不來一點前端技術嘗嘗呢?

這篇文章是學習了公司現有項目框架、外加查閱一些官方文檔之后的總結,受限于我僅有的一丟丟前端知識,如果有錯誤或沒講清楚的地方,歡迎在評論里給我留言 :)

因為要把現有項目講清楚內容較多,所以分為兩個部分來總結。這篇是第一個部分,主要涉及 Redux 思想的簡單應用。


試想一下...

我們從一個實際可能會遇到的需求出發,考慮一下 Native 的實現和 React Native 的實現有什么不同。

來需求了

用戶在登錄之后,在首頁要顯示用戶的頭像和名字,然后還應該可以在某個地方看到自己的全部信息。

( oωo ) 那還不簡單!用戶登錄之后拉一下服務器上的用戶信息,找個合適的界面把信息一股腦顯示出來就好了,done!

簡單地改一下

用戶想要在我們的 App 上編輯自己的信息,我們簡單點來,直接在信息顯示的界面提供個編輯的入口就好了。

∑( ̄□ ̄;) ......嗯,這個要求也合情合理。

編輯之后發個消息通知其他地方,比如首頁的頭像和名字就可能要更新...某個列表似乎會根據用戶性別來決定顯示的內容,不過什么人會用著用著修改性別?!

來,這個更加簡單

果然修改一下用戶信息很簡單嘛,那再改回去也是一個道理吧,提供一個撤銷修改的按鈕吧。

Σ(°Д°; 這!


為什么用 Redux

如何優雅地實現上面的需求呢?如果我們的界面是與數據綁定的,并且數據的每一個狀態我們都可以追蹤到,那我們就不需要理會界面的更新,而可以專注于數據的修改了。

React Native 已經為我們提供了視圖與數據綁定的機制,那么狀態要怎么追蹤呢?

什么是 Redux

Redux 是一個為 JavaScript 應用設計的可預測的狀態容器。

簡單來說,Redux 使用了一種叫做 Action 的東西,每一次對狀態的變更(也就是對數據的變更)都需要通過 Action 來進行,然后通過另一個叫做 Reducer 的東西將 Action 和數據聯系起來。下面這張流程圖應該可以幫助你理解:

Flux

這張圖來自 Flux,Redux 可以被理解為是 Flux 的具體實踐。

顧名思義,Action 是一個操作,也可以理解為將要發生的事件,例如“修改用戶名”、“撤銷修改”;而 Reducer 則位于上圖 Dispatcher 和 Store 之間,負責將 Action 反應到對 Store 的修改上。

初衷

在上面的需求中,如果可以記錄下用戶的每一個操作和操作后的狀態,那么當用戶想要撤銷某項操作時,只需要將上一個操作給無效掉就可以了。更暴力一些,我們把應用啟動至今的所有用戶操作都重播一遍,唯獨不執行最后一次操作,就實現了“撤銷”的功能了吧?

Redux 提供的機制正好滿足了這個需求。

不止如此

React Native 實現的應用可以類比為使用 JavaScript 實現的單頁應用,隨著開發日趨復雜,我們的應用需要管理的狀態(state)會變得越來越多,管理的難度也將成倍增加。

Redux 提供的機制,通過限制數據更新發生的時間和方式,使得 state 的變化變得可以預測,后續的開發也可以放手施展了。


那該怎么做呢?

接下來我們分別看看 Redux 中主要的三部分是怎么實現的。

Action

為了描述一個動作,我們需要給這個動作一個名字和這個動作要操作的數據。舉個栗子,對于用戶想要改變用戶名的情況,我們可以這樣聲明這個動作:

// actions.js

export const CHANGE_USERNAME = 'CHANGE_USERNAME' // 1

// 2
export function changeUsername(username) {
  return { type: CHANGE_USERNAME, username}
}
  1. 首先我們將這個動作稱為 CHANGE_USERNAME,理論上每一個 Action 都應該有一個獨一無二的名字
  2. 通過一個創建函數,創建這個 Action 對象返回給調用方

例子里的動作名和創建函數都是 export 的,因為一般會把同一個模塊的動作聲明放到一起,方便外部的調用。

Reducer

需要注意的是,Reducer 必須是一個純函數。它不能修改傳入的參數并且不能有任何副作用,它必須要保證只要兩次傳入的參數相同,得出的結果也要相同。

先看代碼:

// reducers.js

import { CHANGE_USERNAME } from './actions'

// 1
const initialState = {
  username: ""
}

function demoApp(state = initialState, action) { // 2
  switch (action.type) { // 3
    case CHANGE_USERNAME:
      return { // 4
        ...state,
        username: action.username
      }
      default:
        return state // 5
  }
}

export default demoApp
  1. 在 Redux 應用中,所有的 state 都被保存在一個單一的對象中
  2. 這里用到了 ES6 中的參數默認值語法,省去了初始化 state 的過程
  3. 當需要處理多個 Action 的時候,可以用 switch、if/else 等方式區分不同的處理方式
  4. 再次強調,Reducer 必須是一個純函數,所以使用對象展開運算符把傳入的 state 展開,避免修改到里面的參數
  5. 還是因為純函數的原因,在不處理任何 Action 的時候,需要將傳入的 state 原封不動地再傳回去

通過上面的 Reducer,當有 CHANGE_USERNAME 這個動作發生時,應用會通過 demoApp 方法來更新 state 中的 username 參數,如果有視圖綁定在這個參數上,則界面也會發生相應的改變。

Store

有了 Action 和 Reducer,我們還需要將這二者聯系起來的途徑,稱為 Store。

Store 還具有維持應用 state 的職責,所以它在應用中也是單一存在的。當需要拆分數據處理邏輯的時候,應該做的是拆分 Reducer 而不是創建多個 Store。

繼續來看代碼:

// store.js

import { createStore } from 'redux'
import demoApp from './reducers'
let store = createStore(demoApp)

沒啦!我們需要用到的是 store 里面的方法,所以主要還是來看看怎么使用它們吧。

調用

直接來看代碼,我們假設已經存在一個用戶信息界面,用戶將在這里修改自己的名字:

// UserInfo.js

import { changeUsername } from './actions'
import { store } from './store'

store.dispatch(changeUsername("Lee")) 

在這里,我們通過 changeUsername 方法構造了一個 Action,并告訴它我們要把名字改成什么;通過 store 中的 dispatch 方法,這個 Action 就會被發送 Reducer 中進行處理。

只是寫到這里,得益于純函數的實現,我們就已經可以給上述代碼中的所有方法寫單元測試了,就是這么簡單。


結語

上面的例子只涉及到了 Redux 最基本的使用方式,到目前為止還不能做出什么有用的東西來,不過用來讓我們感受 Redux 的主要思想應該是足夠了。

在下一篇文章中,才會講到 Redux 應用框架的搭建。其中會用到一些能有效減少代碼量的第三方框架(從上面的例子應該不難想象,當程序變復雜之后,這幾個類會變得多么龐大)。如果在學習了基礎知識之后還是看不懂一些現有項目的代碼的話,看完這些第三方框架的使用說不定就懂了呢!

更多更詳細的資料可以看參考資料中的網站。關于 React Native 的部分建議上官網看原版,我發現中文網的翻譯稍有缺失,更新也可能不那么及時。


參考資料:
React Native
React Native 中文網
Redux 中文文檔
RNPlayground

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容