在react-native中使用redux

[2018-07-26 Update, RN版本已更新至0.56版本]
[2017-02-17 Update尘应,github上代碼的RN版本已更新至最新版本(0.41.2)怎茫,如有問(wèn)題請(qǐng)?zhí)醝ssue泞莉,3Q]

redux是什么?

redux是一個(gè)用于管理js應(yīng)用狀態(tài)的容器。redux出現(xiàn)時(shí)間并不是很長(zhǎng),在它出現(xiàn)之前也有類似功能的模塊出現(xiàn),諸如flux等等降狠。redux設(shè)計(jì)的理念很簡(jiǎn)單,似乎最初這個(gè)開發(fā)團(tuán)隊(duì)就有讓redux可以方便融入在server, browser, mobile client端的打算庇楞。目前在github上redux-*的第三方中間件榜配、插件越來(lái)越多。如果react項(xiàng)目中想使用redux姐刁,那么就有react-redux插件來(lái)完成配合芥牌。而作為開發(fā)者,可以使用這些優(yōu)秀的第三方資源來(lái)開發(fā)/優(yōu)化已有的項(xiàng)目聂使,也是一件很歡樂(lè)的事壁拉。

設(shè)計(jì)的動(dòng)機(jī)

在redux.js.org里有關(guān)于編寫redux的動(dòng)機(jī)描述(our code must manage more state than ever before),在現(xiàn)實(shí)的生活中柏靶,單頁(yè)應(yīng)用越來(lái)越多弃理,而且需要維護(hù)的狀態(tài)也越來(lái)越復(fù)雜,諸如維護(hù)數(shù)據(jù)更新屎蜓、UI更新痘昌、本地?cái)?shù)據(jù)存儲(chǔ)等這些都是我們?cè)趈s應(yīng)用常常需要處理的情景,當(dāng)然這里多數(shù)都會(huì)涉及到異步處理炬转。而redux本身就是為了解決這些問(wèn)題辆苔,而是將所有的變化進(jìn)行統(tǒng)一流程處理,會(huì)使我們的程序狀態(tài)變化清晰可見扼劈。redux最終目的就是讓狀態(tài)(state)變化變得可預(yù)測(cè)驻啤。

使用的三原則

  • 1, Single source of truth
    單一數(shù)據(jù)源。整個(gè)應(yīng)用的state荐吵,存儲(chǔ)在唯一一個(gè)object中骑冗,同時(shí)也只有一個(gè)store用于存儲(chǔ)這個(gè)object.
  • 2, State is read-only
    狀態(tài)是只讀的赊瞬。唯一能改變state的方法,就是觸發(fā)action操作贼涩。action是用來(lái)描述正在發(fā)生的事件的一個(gè)對(duì)象巧涧。
  • ** 3, Changes are made with pure functions**
    在改變state tree時(shí),用到action遥倦,同時(shí)也需要編寫對(duì)應(yīng)的reducers才能完成state改變操作谤绳。

在上面的三原則中,我們看到了store, action, reducer這些詞谊迄,那就先說(shuō)說(shuō)redux是怎么進(jìn)行應(yīng)用狀態(tài)(state)維護(hù)管理的呢闷供。

redux狀態(tài)管理的流程

  • action是用戶觸發(fā)或程序觸發(fā)的一個(gè)普通對(duì)象。
  • reducer是根據(jù)action操作來(lái)做出不同的數(shù)據(jù)響應(yīng)统诺,返回一個(gè)新的state歪脏。
  • store的最終值就是由reducer的值來(lái)確定的。(一個(gè)store是一個(gè)對(duì)象, reducer會(huì)改變store中的某些值)


    redux流程.png

上圖簡(jiǎn)單畫了下redux狀態(tài)改變的流程粮呢。action -> reducer -> 新store -> 反饋到UI上有所改變婿失。
下面再給個(gè)具體實(shí)例:

redux登錄實(shí)例.png

store用于維護(hù)狀態(tài)的容器,包括了應(yīng)用的多個(gè)狀態(tài)啄寡,比如說(shuō)用戶是否登錄豪硅、用戶信息、用戶任務(wù)等等挺物。action是一個(gè)普通對(duì)象懒浮,用于指明是哪種操作,這樣才能在reducers中進(jìn)行識(shí)別识藤。而眾多reducer是負(fù)責(zé)返回新的state的函數(shù)砚著。在實(shí)際應(yīng)用中,你需要將store或store的某個(gè)值綁定到界面痴昧,這樣更新store的時(shí)候稽穆,該頁(yè)面可以監(jiān)聽到值的更新,然后進(jìn)行一些頁(yè)面更新操作/跳轉(zhuǎn)操作等赶撰。

redux在實(shí)際使用中需要用到的高級(jí)部分

redux設(shè)計(jì)如此簡(jiǎn)潔舌镶,以至于并沒有進(jìn)行異步處理的功能餐胀。但是留下了middleware這個(gè)概念惕虑。可以自己編寫符合需要的中間件。目前第三方的中間件基本可以完成一個(gè)復(fù)雜應(yīng)用的架構(gòu)設(shè)計(jì)。那就先說(shuō)一說(shuō)暗膜,怎么去處理異步請(qǐng)求呢瑞佩。
首先推薦redux-thunk蜒蕾,可以看到它的源碼很簡(jiǎn)潔瑟匆。就是判斷action是否是函數(shù),如果是函數(shù)進(jìn)行遞歸式的操作渐扮。所以在redux中的異步膀估,只能出現(xiàn)在action中饼记,而且還需要有中間件的支持。

 export default function thunkMiddleware({ dispatch, getState }) {
       return next => action => {
          if (typeof action === 'function') {
              return action(dispatch, getState);
          }
        return next(action);
      };
 }
// redux-thunk的源碼

同步action與異步action最大的區(qū)別是:
同步只返回一個(gè)普通action對(duì)象束昵。而異步操作中途會(huì)返回一個(gè)promise函數(shù)巴比。當(dāng)然在promise函數(shù)處理完畢后也會(huì)返回一個(gè)普通action對(duì)象。thunk中間件就是判斷如果返回的是函數(shù)礁遵,則不傳導(dǎo)給reducer轻绞,直到檢測(cè)到是普通action對(duì)象,才交由reducer處理佣耐。

實(shí)例說(shuō)說(shuō)redux的使用政勃。

實(shí)例代碼在github上查看地址。該實(shí)例只演示了登錄過(guò)程兼砖,是比較基礎(chǔ)的redux使用案例奸远。

目錄結(jié)構(gòu)

項(xiàng)目相關(guān)代碼均在js目錄下。目錄中可以看到actions, reducers, store等子目錄讽挟。

實(shí)例action

actions/user.js

actions/user.js目錄中定義了用戶登錄操作的action creator

  • 第22行的logIn
    logIn是一個(gè)異步action懒叛,注意函數(shù)內(nèi)部的寫法與redux-thunk的定義要相同。
  • 第38行的skipLogin
  • 第47行logOut
    這些creator耽梅,產(chǎn)生的action狀態(tài)有LOGGED_DOING, LOGGED_IN, LOGGED_ERROR, LOGGED_OUT四種狀態(tài)薛窥。
    第8行變量testUser, 第15行變量skipUser分別是模擬針對(duì)普通登錄成功后(這里用的是fetch www.baidu.com,真實(shí)情況下需換成真實(shí)的登錄接口)的用戶對(duì)象眼姐,跳過(guò)登錄后默認(rèn)的用戶對(duì)象诅迷。
    接下來(lái)再看看reducers怎么去處理這些action?

實(shí)例reducer

reducers/user.js

reducers/user.js中:

  • 第5行的initialState定義了最開始的應(yīng)用狀態(tài)(即用戶未登錄的情況下的state)佩番。
  • 第13行,對(duì)每個(gè)傳過(guò)來(lái)的action進(jìn)行switch竟贯,每個(gè)action都需要返回一個(gè)state對(duì)象答捕,如果不需要變動(dòng),則返回原對(duì)象(switch中的default返回值)屑那。需要變動(dòng),則返回一個(gè)新的state, 可以看到當(dāng)type為LOGGED_DOING,LOGGED_IN, LOGGED_OUT時(shí)艘款,返回的對(duì)象跟原始對(duì)象都會(huì)有一些字段的差別持际。
reducers/index.js

reducers/index.js中:

  • 第5行combineReducers是將應(yīng)用的state進(jìn)行組合。
  • 目前demo中只有用戶信息哗咆,所以只看到第6行userStore這一個(gè)key蜘欲,在一個(gè)業(yè)務(wù)復(fù)雜的應(yīng)用里,需要保存很多應(yīng)用和用戶交互產(chǎn)生的信息(比如說(shuō)用戶聊天列表等信息)晌柬。

實(shí)例store

再來(lái)看看store的處理:

store/index.js

store/index.js中定義了store的行為(包括中間件):

  • 第23行的applyMiddleware會(huì)將中間件應(yīng)用在redux action過(guò)程中姥份。
  • 第10行自定義一個(gè)logger中間件,該中間件的目的是打印出當(dāng)前的觸發(fā)的action以及出發(fā)后的state變化年碘。
  • 第27行澈歉,33行 使用了redux-persist這個(gè)第三方插件來(lái)將store對(duì)象存儲(chǔ)到本地,以及從本地恢復(fù)數(shù)據(jù)到store中屿衅,比如說(shuō)保存登錄信息埃难,下次打開應(yīng)用可以直接跳過(guò)登錄界面。

程序入口

上面是定義涤久。下面再來(lái)看如何在程序中使用:

程序入口index.js

在入口文件index.js中:

  • 第27行涡尘,需要將store作為屬性傳遞給Provider組件中。
  • 第28行响迂,可以看到的是真正渲染出的東西是<Root/>標(biāo)簽返回的東西考抄。

那就來(lái)看看root.js里的內(nèi)容。

root.js

root.js中:

  • 第48行的render主要實(shí)現(xiàn)了Navigator導(dǎo)航器的處理蔗彤,并用自定義的一個(gè)Router(第27行)進(jìn)行封裝了下川梅。
  • 第59行,在末尾的select函數(shù)幕与,是將store中的某些值復(fù)制到當(dāng)前組件的props中挑势,注意這里需要用connect函數(shù)進(jìn)行綁定,否則store變化啦鸣,不會(huì)反饋到Root組件中潮饱。isLoggedIn這個(gè)變量便被復(fù)制到當(dāng)前的Root組件中,在Root內(nèi)部方法中可以訪問(wèn)诫给。
  • 第16行香拉,constructor里啦扬,會(huì)對(duì)登錄狀態(tài)進(jìn)行判斷,如果檢測(cè)到已經(jīng)登錄了凫碌,則會(huì)修改Navigator初始的路由設(shè)置(第10行設(shè)置的)扑毡,使應(yīng)用直接顯示MainPage

登錄頁(yè)面盛险。

那再看看登錄頁(yè)面pages/login.js中的用戶操作:

pages/login.js - 1
pages/login.js - 2
pages/login.js - 3

上面的3個(gè)圖片是整個(gè)pages/login.js的源碼瞄摊。

  • 第160行,指定了該組件會(huì)與store的哪些值進(jìn)行連接苦掘。分別是isLoggedIn, user, status换帜。
  • 第129行,定義了TextonPress操作鹤啡。handleLogin是綁定的操作方法惯驼,方法內(nèi)容見第60行。在71行時(shí)递瑰,會(huì)觸發(fā)logIn這個(gè)action祟牲。
  • 觸發(fā)logIn后,會(huì)先進(jìn)入LOGGED_DOING狀態(tài)抖部,此時(shí)說(shuō)明在登錄中说贝。在第42行,有對(duì)該狀態(tài)進(jìn)行監(jiān)聽您朽,如果為該狀態(tài)狂丝,會(huì)將彈窗彈出,提醒為loading態(tài)哗总。
  • 第33行几颜,在shouldComponentUpdate中,對(duì)即將變化的nextProps進(jìn)行與目前的props進(jìn)行對(duì)比讯屈。比如說(shuō)logIn執(zhí)行登錄完成后蛋哭,第35行檢測(cè)到isLoggedIn為true,則執(zhí)行toMain函數(shù)(即跳轉(zhuǎn)到主頁(yè)中)涮母。

看下最終的demo交互效果谆趾。

demo交互效果

推薦:
RNTools是一個(gè)分享React Native文章、實(shí)例代碼以及第三方模塊的平臺(tái)叛本。RNTools官網(wǎng)鏈接 RNTools應(yīng)用下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沪蓬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子来候,更是在濱河造成了極大的恐慌跷叉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異云挟,居然都是意外死亡梆砸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門园欣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)帖世,“玉大人,你說(shuō)我怎么就攤上這事沸枯∪战茫” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵绑榴,是天一觀的道長(zhǎng)搬男。 經(jīng)常有香客問(wèn)我,道長(zhǎng)彭沼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任备埃,我火速辦了婚禮姓惑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘按脚。我一直安慰自己于毙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布辅搬。 她就那樣靜靜地躺著唯沮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堪遂。 梳的紋絲不亂的頭發(fā)上介蛉,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音溶褪,去河邊找鬼币旧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛猿妈,可吹牛的內(nèi)容都是我干的吹菱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼彭则,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鳍刷!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起俯抖,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤输瓜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體前痘,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凛捏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芹缔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坯癣。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖最欠,靈堂內(nèi)的尸體忽然破棺而出示罗,到底是詐尸還是另有隱情,我是刑警寧澤芝硬,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布蚜点,位于F島的核電站,受9級(jí)特大地震影響拌阴,放射性物質(zhì)發(fā)生泄漏绍绘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一迟赃、第九天 我趴在偏房一處隱蔽的房頂上張望陪拘。 院中可真熱鬧,春花似錦纤壁、人聲如沸左刽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欠痴。三九已至,卻和暖如春秒咨,著一層夾襖步出監(jiān)牢的瞬間喇辽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工拭荤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茵臭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓舅世,卻偏偏與公主長(zhǎng)得像旦委,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雏亚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容