Redux 學(xué)習(xí)紀(jì)要

背景

Redux 是 React 全家桶的重要一員,理解 Redux 可以更好的幫助我們開(kāi)發(fā)前端項(xiàng)目霍比。本文只談?wù)摳拍畹慕庾x幕袱,不講解具體的用法。

Redux 和 React-Redux

首先聲明 Redux 和 React-Redux 的區(qū)別悠瞬。 Redux 這個(gè)項(xiàng)目嚴(yán)格來(lái)說(shuō)们豌,并不局限于 React,它可以用于 ES6, Angular 浅妆,React望迎。而 React-Redux 是 React 官方提供的一個(gè)集成 Redux 的包。

為什么要 Redux

這個(gè)要從 React 的哲學(xué)講起凌外,在 React 中辩尊,有兩個(gè)重要的概念 props 和 state,
props 一般是外部組件傳入的趴乡,而 state 是組件內(nèi)部的狀態(tài)对省。也就是說(shuō)數(shù)據(jù)從外部更大的組件傳遞到內(nèi)部被包含的數(shù)據(jù)。

React 中的數(shù)據(jù)流向

這樣的方式晾捏,非常直觀蒿涎,對(duì)于一些平鋪式的頁(yè)面非常有優(yōu)勢(shì),比如資訊類(lèi)應(yīng)用惦辛,資訊只需要瀑布流式的展示劳秋,資訊之間沒(méi)有交互。

可是并不是所有的頁(yè)面都那么簡(jiǎn)單,也有很多場(chǎng)景玻淑,我們頁(yè)面組件之間還是需要交互的嗽冒,這個(gè)時(shí)候就不一樣了。組件之間的關(guān)系是平級(jí)的补履,沒(méi)法直接傳遞數(shù)據(jù)的添坊。

組件無(wú)法直接傳遞數(shù)據(jù)

沒(méi)有 Redux 的情況

針對(duì)非包含關(guān)系的組件間傳遞數(shù)據(jù)的問(wèn)題,React 官方文檔提到了一種解決辦法箫锤,見(jiàn) Lifting State Up, 其思路其實(shí)是添加一個(gè)組件贬蛙,我們暫時(shí)稱(chēng)它為外包組件,讓它包含需要交互的兩個(gè)組件谚攒,然后通過(guò)被包含的組件觸發(fā) callback 方法阳准,引起外包組件變化,然后外包組件再修改另一個(gè)組件馏臭。

callback 方式傳遞數(shù)據(jù)

這當(dāng)然是解決問(wèn)題的一種方式野蝇,但是這種方式卻會(huì)帶來(lái)一個(gè)問(wèn)題,因?yàn)橐坏┬枰换サ慕M件最近公共外包組件特別遠(yuǎn)的話括儒,需要大量地修改代碼,一層一層的傳遞 callback 函數(shù)绕沈。這樣的工作量簡(jiǎn)直不要太大。

當(dāng)組件支架的最近公共外包組件很遠(yuǎn)的時(shí)候塑崖,callback簡(jiǎn)直崩潰

Redux 是怎么做的

在寫(xiě) React 的時(shí)候七冲,通常我看到一個(gè)前端組件的時(shí)候,我們總是很自然的認(rèn)為組件應(yīng)該包含 view 和 state 兩個(gè)部分规婆。組件應(yīng)該高內(nèi)聚的維護(hù)其 view 和 state澜躺。 但是 Redux 不這么思考, Redux 認(rèn)為組件最好只維護(hù) view , 而 state 應(yīng)該在一個(gè)地方集中的維護(hù)抒蚜。

redex 數(shù)據(jù)集中化管理圖示

Redux 將所有的數(shù)據(jù)掘鄙,集中在一個(gè)地方,組件可以直接引用這個(gè)數(shù)據(jù)源嗡髓,同樣也有了修改這個(gè)公共數(shù)據(jù)源的能力操漠。通過(guò)這樣的方式解決了組件間數(shù)據(jù)流動(dòng)的問(wèn)題。

Redux 中重要的概念

知道了 Redux 做了什么饿这,現(xiàn)在我們來(lái)看看 Redux 為了實(shí)現(xiàn)這些功能浊伙,都提供了哪些概念。

Store

store 就是存儲(chǔ)全局?jǐn)?shù)據(jù)的地方长捧。組件可以通過(guò)連接到 store 來(lái)獲取到全局的數(shù)據(jù)嚣鄙。

Action

當(dāng)組件可以通過(guò)連接 store 來(lái)查看和修改全局?jǐn)?shù)據(jù),用于觸發(fā)變更串结。但是比起直接修改 store哑子,更好的方法是使用命令模式舅列,組件只需要發(fā)布命令就好了,然后讓具體的執(zhí)行者去執(zhí)行卧蜓,這樣就可以將命令和執(zhí)行解耦開(kāi)帐要。 Redux 使用了這樣的設(shè)計(jì)模式,組件發(fā)送命令,然后由 Reducers 去執(zhí)行具體的命令弥奸。而 Redux 的 action 正是命令模式中的 command 榨惠。action 中包含命令的類(lèi)型 type 和命令的內(nèi)容。

Reducers

Reducers 就是命令模式中的命令接受者盛霎,Reducers 接受到 action冒冬,然后根據(jù) action 的內(nèi)容去對(duì) store 執(zhí)行相應(yīng)的變更操作。

pure function (純函數(shù))

Reducers 的具體實(shí)現(xiàn)其實(shí)就是一個(gè)大的函數(shù)摩渺,Redux 官方文檔聲明成為 Reducers 的函數(shù)必須是一個(gè) pure funciton。所謂純函數(shù)和我們常說(shuō)的無(wú)副作用函數(shù)是有區(qū)別的剂邮。

純函數(shù): 在任何時(shí)刻摇幻,對(duì)于給定的一個(gè)入?yún)ⅲ挥形ㄒ灰粋€(gè)對(duì)應(yīng)的結(jié)果

根據(jù)上述的定義挥萌,類(lèi)似 f(x) = x + 1绰姻。 這樣簡(jiǎn)單的函數(shù)就是純函數(shù),純函數(shù)最主要的概念是將時(shí)間區(qū)分出來(lái)了引瀑,所以類(lèi)似向服務(wù)端發(fā)起請(qǐng)求獲取文章 pv 的接口就不是純函數(shù)狂芋,因?yàn)?pv 會(huì)隨著時(shí)間的推移而發(fā)生改變。之所以要求是純函數(shù)憨栽,據(jù) Redux 作者在自己的博客 The Evolution of Flux Frameworks 中所說(shuō)的

Stores and actions are just pure functions. They are easily testable in isolation.

主要是為了易于測(cè)試帜矾,因?yàn)榧兒瘮?shù)便于做重放操作。

dispatch

顧名思義屑柔,就是分發(fā)器方法屡萤,負(fù)責(zé)將 action 分發(fā)到 Reducers 。

subsribe

訂閱方法掸宛,參數(shù)是監(jiān)聽(tīng)器死陆,監(jiān)聽(tīng) store 的變更事件,當(dāng) store 發(fā)生變化的時(shí)候唧瘾,觸發(fā)回調(diào)函數(shù)

connect

這個(gè)方法功能主要的是將當(dāng)前組件和全局的 store 連接措译,并將 dispatch 注入到當(dāng)前的組件的 props 中。 當(dāng) store 更新的時(shí)候饰序,會(huì)通過(guò) connect 傳入的回調(diào)函數(shù)將更新后的數(shù)據(jù)通知到當(dāng)前組件领虹。而且由于 connect 可以方便的指定當(dāng)前組件需要關(guān)心的數(shù)據(jù),所以用了 connect 后菌羽, subsribe 基本上就沒(méi)有使用必要了掠械。

Redux 數(shù)據(jù)流程

Redux 數(shù)據(jù)流程

Store 與 render 的觸發(fā)

當(dāng) store 發(fā)生變化的時(shí)候由缆,會(huì)通過(guò) connect 中的回調(diào)函數(shù)觸發(fā)組件重新 render,以此來(lái)改變頁(yè)面內(nèi)容猾蒂。

Store 的局部改變

當(dāng) store 發(fā)生改變的時(shí)候均唉,改變的數(shù)據(jù)可能只是局部的一小部分,當(dāng)小部分?jǐn)?shù)據(jù)發(fā)生變更的時(shí)候肚菠,redux 會(huì)只更新局部的 view 舔箭,而其它不發(fā)生改變,這樣有助于提升性能蚊逢。

如何判斷數(shù)據(jù)是否更新

數(shù)據(jù)要更新了才能觸發(fā) render层扶,但是如何判斷數(shù)據(jù)已經(jīng)發(fā)生改變了呢。眾所周知烙荷,對(duì)于嵌套層次特別深的數(shù)據(jù)镜会,很難判斷數(shù)據(jù)是否 update,而且如果要判斷终抽,必須遞歸地判斷戳表,這樣性能是比較差的,所以 react-redux 使用了淺層判斷的方式昼伴,類(lèi)比 C++ 和 Java 其實(shí)就是判斷對(duì)象的內(nèi)存地址匾旭,在 JavaScript 中其實(shí)就是 == 判斷。

嵌套判斷

因?yàn)槭褂昧藴\層判斷圃郊,所以對(duì)于一個(gè)數(shù)據(jù)价涝,比如 a.b.c.d ,如果我們要更新 d 數(shù)據(jù)持舆,如果我們只更新了 d色瘩,是不夠的,因?yàn)?a 沒(méi)有更新逸寓,無(wú)法通過(guò)淺層判斷泞遗。但是僅僅更新 a,d 也不夠,因?yàn)榈搅?b 依舊無(wú)法通過(guò)淺層判斷席覆,所以如果要更新d ,則 d,c,b,a 都要更新史辙,也即更新一個(gè)數(shù)據(jù),其所有的父對(duì)象也都要更新佩伤。
這個(gè)要特別關(guān)注聊倔,因?yàn)榻?jīng)常出現(xiàn)的頁(yè)面沒(méi)有重新 render 的原因,大多是因?yàn)闆](méi)有重新生成父對(duì)象生巡。

Redux 和傳統(tǒng)的 發(fā)布/訂閱 系統(tǒng)

雖然 Redux 中也有發(fā)布和訂閱耙蔑,但和我們通常使用的基于觀察者模式的 發(fā)布/訂閱系統(tǒng)卻有所不同。

Redux 添加組件不符合開(kāi)閉原則

我們常用的發(fā)布/訂閱模型孤荣,訂閱者向消息中心訂閱消息甸陌,然后收到消息须揣,在這個(gè)過(guò)程中,不需要修改現(xiàn)有代碼钱豁,而在 Redux 中添加組件耻卡,不僅需要修改初始化 store,還需要修改 redurces ,用于配合修改新添加的組件的 state。在這個(gè)過(guò)程中存在代碼修改牲尺,不符合開(kāi)閉原則卵酪。

沒(méi)有消息堆積功能

Redux 中沒(méi)有原生的消息堆積的概念。

組件不符合內(nèi)聚性

使用了 Redux 的組件谤碳,因?yàn)槠浜腿孔兞拷壎ɡ?ǎ簿鸵馕吨驼麄€(gè)應(yīng)用緊耦合了,這是不符合高內(nèi)聚原則的蜒简,也即意味著使用了 Redux 的組件跨應(yīng)用的復(fù)用性差瘸羡,所以 Redux 更適合開(kāi)發(fā)有復(fù)雜交互的 webApp,而不適合用于開(kāi)發(fā)需要高可復(fù)用性的組件搓茬。如果自己開(kāi)發(fā)的組件也有一定的交互最铁,可以考慮自行開(kāi)發(fā)一套簡(jiǎn)易的發(fā)布/訂閱工具。我在我自己的項(xiàng)目中垮兑,開(kāi)發(fā)的組件,為了能不用 redux 實(shí)現(xiàn)消息的訂閱和發(fā)布漱挎,自行開(kāi)發(fā)了如下簡(jiǎn)易的發(fā)布/訂閱工具

const dispatchMap = [];

export function registerListener(topic,callback,tags = '*'){
    let listener = {
        topic: topic,
        tags: tags,
        callback: callback
    };
    dispatchMap.push(listener);
}

export function publish(msg){
    dispatchMap.forEach( (listener) => {
        if(listener.topic == msg.topic){
            if(listener.tags === '*' || listener.tags.includes(msg.tag)){
                listener.callback(msg.content);
            }
        }
    });
}

總結(jié)

redux 之所以能在 react 中流行系枪,歸根結(jié)底是因?yàn)樗芙鉀Q react 中數(shù)據(jù)流動(dòng)性差的問(wèn)題,搞明白這點(diǎn)之后磕谅,很多 redux 的設(shè)計(jì)也就能理解了私爷。所以說(shuō)學(xué)習(xí)一個(gè)新的東西,我認(rèn)為最重要的部分膊夹,是先學(xué)習(xí)我們?yōu)槭裁葱枰幕耄?dāng)我們搞明白為什么需要它之后,然后再學(xué)習(xí)它是怎么解決的放刨,就會(huì)少很多疑惑工秩,不會(huì)一來(lái)看到一大把術(shù)語(yǔ)而不知所措。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末进统,一起剝皮案震驚了整個(gè)濱河市助币,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌螟碎,老刑警劉巖眉菱,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異掉分,居然都是意外死亡俭缓,警方通過(guò)查閱死者的電腦和手機(jī)克伊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)华坦,“玉大人愿吹,你說(shuō)我怎么就攤上這事〖敬海” “怎么了洗搂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)载弄。 經(jīng)常有香客問(wèn)我耘拇,道長(zhǎng),這世上最難降的妖魔是什么宇攻? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任惫叛,我火速辦了婚禮,結(jié)果婚禮上逞刷,老公的妹妹穿的比我還像新娘嘉涌。我一直安慰自己,他們只是感情好夸浅,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布仑最。 她就那樣靜靜地躺著,像睡著了一般帆喇。 火紅的嫁衣襯著肌膚如雪警医。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天坯钦,我揣著相機(jī)與錄音预皇,去河邊找鬼。 笑死婉刀,一個(gè)胖子當(dāng)著我的面吹牛吟温,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播突颊,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鲁豪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了律秃?” 一聲冷哼從身側(cè)響起呈昔,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎友绝,沒(méi)想到半個(gè)月后堤尾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迁客,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年郭宝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辞槐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粘室,死狀恐怖榄檬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衔统,我是刑警寧澤鹿榜,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站锦爵,受9級(jí)特大地震影響舱殿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜险掀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一沪袭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧樟氢,春花似錦冈绊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至碴开,卻和暖如春毅该,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叹螟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留台盯,地道東北人罢绽。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像静盅,于是被迫代替她去往敵國(guó)和親良价。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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

  • http://gaearon.github.io/redux/index.html 蒿叠,文檔在 http://rac...
    jacobbubu閱讀 79,900評(píng)論 35 198
  • 看到這篇文章build an image gallery using redux saga明垢,覺(jué)得寫(xiě)的不錯(cuò),長(zhǎng)短也適...
    smartphp閱讀 6,141評(píng)論 1 29
  • 前言 本文 有配套視頻市咽,可以酌情觀看痊银。 文中內(nèi)容因各人理解不同,可能會(huì)有所偏差施绎,歡迎朋友們聯(lián)系我討論溯革。 文中所有內(nèi)...
    珍此良辰閱讀 11,894評(píng)論 23 111
  • React 在 React 中贞绳,UI 以組件的形式來(lái)搭建,組件之間可以嵌套組合致稀。另冈闭,React 中組件間通信的數(shù)據(jù)...
    RN學(xué)習(xí)閱讀 1,009評(píng)論 0 6
  • 學(xué)習(xí)必備要點(diǎn): 首先弄明白,Redux在使用React開(kāi)發(fā)應(yīng)用時(shí)抖单,起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,877評(píng)論 10 58