博客地址:http://davidleee.com
原文鏈接:http://davidleee.com/2017/04/20/Build-App-With-Redux/
自從 Facebook 把 React Native 給開源了之后,使用前端技術(shù)進行移動應(yīng)用開發(fā)的趨勢已經(jīng)越來越明顯赖草,現(xiàn)在連微軟爸爸都用上了 React Native(ReactXP)往果,我們還有什么理由不來一點前端技術(shù)嘗嘗呢?
這篇文章是學(xué)習(xí)了公司現(xiàn)有項目框架围来、外加查閱一些官方文檔之后的總結(jié)底扳,受限于我僅有的一丟丟前端知識请垛,如果有錯誤或沒講清楚的地方餐抢,歡迎在評論里給我留言 :)
因為要把現(xiàn)有項目講清楚內(nèi)容較多,所以分為兩個部分來總結(jié)荐绝。這篇是第一個部分一汽,主要涉及 Redux 思想的簡單應(yīng)用。
試想一下...
我們從一個實際可能會遇到的需求出發(fā)低滩,考慮一下 Native 的實現(xiàn)和 React Native 的實現(xiàn)有什么不同召夹。
來需求了
用戶在登錄之后,在首頁要顯示用戶的頭像和名字恕沫,然后還應(yīng)該可以在某個地方看到自己的全部信息监憎。
( oωo ) 那還不簡單!用戶登錄之后拉一下服務(wù)器上的用戶信息婶溯,找個合適的界面把信息一股腦顯示出來就好了鲸阔,done!
簡單地改一下
用戶想要在我們的 App 上編輯自己的信息迄委,我們簡單點來隶债,直接在信息顯示的界面提供個編輯的入口就好了。
∑( ̄□ ̄;) ......嗯跑筝,這個要求也合情合理死讹。
編輯之后發(fā)個消息通知其他地方,比如首頁的頭像和名字就可能要更新...某個列表似乎會根據(jù)用戶性別來決定顯示的內(nèi)容曲梗,不過什么人會用著用著修改性別赞警?!
來虏两,這個更加簡單
果然修改一下用戶信息很簡單嘛愧旦,那再改回去也是一個道理吧,提供一個撤銷修改的按鈕吧定罢。
Σ(°Д°; 這笤虫!
為什么用 Redux
如何優(yōu)雅地實現(xiàn)上面的需求呢?如果我們的界面是與數(shù)據(jù)綁定的祖凫,并且數(shù)據(jù)的每一個狀態(tài)我們都可以追蹤到琼蚯,那我們就不需要理會界面的更新,而可以專注于數(shù)據(jù)的修改了惠况。
React Native 已經(jīng)為我們提供了視圖與數(shù)據(jù)綁定的機制遭庶,那么狀態(tài)要怎么追蹤呢?
什么是 Redux
Redux 是一個為 JavaScript 應(yīng)用設(shè)計的可預(yù)測的狀態(tài)容器稠屠。
簡單來說峦睡,Redux 使用了一種叫做 Action 的東西翎苫,每一次對狀態(tài)的變更(也就是對數(shù)據(jù)的變更)都需要通過 Action 來進行,然后通過另一個叫做 Reducer 的東西將 Action 和數(shù)據(jù)聯(lián)系起來榨了。下面這張流程圖應(yīng)該可以幫助你理解:
這張圖來自 Flux煎谍,Redux 可以被理解為是 Flux 的具體實踐。
顧名思義龙屉,Action 是一個操作呐粘,也可以理解為將要發(fā)生的事件,例如“修改用戶名”叔扼、“撤銷修改”;而 Reducer 則位于上圖 Dispatcher 和 Store 之間漫雷,負責將 Action 反應(yīng)到對 Store 的修改上瓜富。
初衷
在上面的需求中,如果可以記錄下用戶的每一個操作和操作后的狀態(tài)降盹,那么當用戶想要撤銷某項操作時与柑,只需要將上一個操作給無效掉就可以了。更暴力一些蓄坏,我們把應(yīng)用啟動至今的所有用戶操作都重播一遍价捧,唯獨不執(zhí)行最后一次操作,就實現(xiàn)了“撤銷”的功能了吧涡戳?
Redux 提供的機制正好滿足了這個需求结蟋。
不止如此
React Native 實現(xiàn)的應(yīng)用可以類比為使用 JavaScript 實現(xiàn)的單頁應(yīng)用,隨著開發(fā)日趨復(fù)雜渔彰,我們的應(yīng)用需要管理的狀態(tài)(state)會變得越來越多嵌屎,管理的難度也將成倍增加。
Redux 提供的機制恍涂,通過限制數(shù)據(jù)更新發(fā)生的時間和方式宝惰,使得 state 的變化變得可以預(yù)測,后續(xù)的開發(fā)也可以放手施展了再沧。
那該怎么做呢尼夺?
接下來我們分別看看 Redux 中主要的三部分是怎么實現(xiàn)的。
Action
為了描述一個動作炒瘸,我們需要給這個動作一個名字和這個動作要操作的數(shù)據(jù)淤堵。舉個栗子,對于用戶想要改變用戶名的情況顷扩,我們可以這樣聲明這個動作:
// actions.js
export const CHANGE_USERNAME = 'CHANGE_USERNAME' // 1
// 2
export function changeUsername(username) {
return { type: CHANGE_USERNAME, username}
}
- 首先我們將這個動作稱為
CHANGE_USERNAME
粘勒,理論上每一個 Action 都應(yīng)該有一個獨一無二的名字 - 通過一個創(chuàng)建函數(shù),創(chuàng)建這個 Action 對象返回給調(diào)用方
例子里的動作名和創(chuàng)建函數(shù)都是 export
的屎即,因為一般會把同一個模塊的動作聲明放到一起庙睡,方便外部的調(diào)用事富。
Reducer
需要注意的是,Reducer 必須是一個純函數(shù)乘陪。它不能修改傳入的參數(shù)并且不能有任何副作用统台,它必須要保證只要兩次傳入的參數(shù)相同,得出的結(jié)果也要相同啡邑。
先看代碼:
// 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
- 在 Redux 應(yīng)用中贱勃,所有的
state
都被保存在一個單一的對象中 - 這里用到了 ES6 中的參數(shù)默認值語法,省去了初始化
state
的過程 - 當需要處理多個 Action 的時候谤逼,可以用
switch
贵扰、if/else
等方式區(qū)分不同的處理方式 - 再次強調(diào),Reducer 必須是一個純函數(shù)流部,所以使用對象展開運算符把傳入的
state
展開戚绕,避免修改到里面的參數(shù) - 還是因為純函數(shù)的原因,在不處理任何 Action 的時候枝冀,需要將傳入的
state
原封不動地再傳回去
通過上面的 Reducer舞丛,當有 CHANGE_USERNAME
這個動作發(fā)生時,應(yīng)用會通過 demoApp
方法來更新 state
中的 username
參數(shù)果漾,如果有視圖綁定在這個參數(shù)上球切,則界面也會發(fā)生相應(yīng)的改變。
Store
有了 Action 和 Reducer绒障,我們還需要將這二者聯(lián)系起來的途徑吨凑,稱為 Store。
Store 還具有維持應(yīng)用 state
的職責户辱,所以它在應(yīng)用中也是單一存在的怀骤。當需要拆分數(shù)據(jù)處理邏輯的時候,應(yīng)該做的是拆分 Reducer 而不是創(chuàng)建多個 Store焕妙。
繼續(xù)來看代碼:
// store.js
import { createStore } from 'redux'
import demoApp from './reducers'
let store = createStore(demoApp)
沒啦蒋伦!我們需要用到的是 store
里面的方法,所以主要還是來看看怎么使用它們吧焚鹊。
調(diào)用
直接來看代碼痕届,我們假設(shè)已經(jīng)存在一個用戶信息界面,用戶將在這里修改自己的名字:
// UserInfo.js
import { changeUsername } from './actions'
import { store } from './store'
store.dispatch(changeUsername("Lee"))
在這里末患,我們通過 changeUsername
方法構(gòu)造了一個 Action研叫,并告訴它我們要把名字改成什么;通過 store
中的 dispatch
方法璧针,這個 Action 就會被發(fā)送 Reducer 中進行處理嚷炉。
只是寫到這里,得益于純函數(shù)的實現(xiàn)探橱,我們就已經(jīng)可以給上述代碼中的所有方法寫單元測試了申屹,就是這么簡單绘证。
結(jié)語
上面的例子只涉及到了 Redux 最基本的使用方式,到目前為止還不能做出什么有用的東西來哗讥,不過用來讓我們感受 Redux 的主要思想應(yīng)該是足夠了嚷那。
在下一篇文章中,才會講到 Redux 應(yīng)用框架的搭建杆煞。其中會用到一些能有效減少代碼量的第三方框架(從上面的例子應(yīng)該不難想象魏宽,當程序變復(fù)雜之后,這幾個類會變得多么龐大)决乎。如果在學(xué)習(xí)了基礎(chǔ)知識之后還是看不懂一些現(xiàn)有項目的代碼的話队询,看完這些第三方框架的使用說不定就懂了呢!
更多更詳細的資料可以看參考資料中的網(wǎng)站构诚。關(guān)于 React Native 的部分建議上官網(wǎng)看原版蚌斩,我發(fā)現(xiàn)中文網(wǎng)的翻譯稍有缺失,更新也可能不那么及時唤反。
參考資料:
React Native
React Native 中文網(wǎng)
Redux 中文文檔
RNPlayground