React總結(jié)文檔

做React需要會什么继效?

react的功能其實(shí)很單一,主要負(fù)責(zé)渲染的功能豫尽,現(xiàn)有的框架,比如angular是一個(gè)大而全的框架顷帖,用了angular幾乎就不需要用其他工具輔助配合美旧,但是react不一樣,他只負(fù)責(zé)ui渲染贬墩,想要做好一個(gè)項(xiàng)目榴嗅,往往需要其他庫和工具的配合,比如用redux來管理數(shù)據(jù)陶舞,react-router管理路由嗽测,react已經(jīng)全面擁抱es6,所以es6也得掌握肿孵,webpack就算是不會配置也要會用唠粥,要想提高性能疏魏,需要按需加載,immutable.js也得用上晤愧,還有單元測試……

http://www.tuicool.com/articles/eAbii23

React 是什么

用腳本進(jìn)行DOM操作的代價(jià)很昂貴大莫。有個(gè)貼切的比喻,把DOM和JavaScript各自想象為一個(gè)島嶼养涮,它們之間用收費(fèi)橋梁連接葵硕,js每次訪問DOM,都要途徑這座橋贯吓,并交納“過橋費(fèi)”,訪問DOM的次數(shù)越多懈凹,費(fèi)用也就越高。 因此悄谐,推薦的做法是盡量減少過橋的次數(shù)介评,努力待在ECMAScript島上。因?yàn)檫@個(gè)原因react的虛擬dom就顯得難能可貴了爬舰,它創(chuàng)造了虛擬dom并且將它們儲存起來们陆,每當(dāng)狀態(tài)發(fā)生變化的時(shí)候就會創(chuàng)造新的虛擬節(jié)點(diǎn)和以前的進(jìn)行對比,讓變化的部分進(jìn)行渲染情屹。整個(gè)過程沒有對dom進(jìn)行獲取和操作坪仇,只有一個(gè)渲染的過程,所以react說是一個(gè)ui框架垃你。

React的組件化

react的一個(gè)組件很明顯的由dom視圖和state數(shù)據(jù)組成椅文,兩個(gè)部分涇渭分明。state是數(shù)據(jù)中心惜颇,它的狀態(tài)決定著視圖的狀態(tài)皆刺。這時(shí)候發(fā)現(xiàn)似乎和我們一直推崇的MVC開發(fā)模式有點(diǎn)區(qū)別,沒了Controller控制器凌摄,那用戶交互怎么處理羡蛾,數(shù)據(jù)變化誰來管理?然而這并不是react所要關(guān)心的事情锨亏,它只負(fù)責(zé)ui的渲染痴怨。與其他框架監(jiān)聽數(shù)據(jù)動態(tài)改變dom不同,react采用setState來控制視圖的更新器予。setState會自動調(diào)用render函數(shù)浪藻,觸發(fā)視圖的重新渲染,如果僅僅只是state數(shù)據(jù)的變化而沒有調(diào)用setState劣摇,并不會觸發(fā)更新珠移。 組件就是擁有獨(dú)立功能的視圖模塊弓乙,許多小的組件組成一個(gè)大的組件末融,整個(gè)頁面就是由一個(gè)個(gè)組件組合而成钧惧。它的好處是利于重復(fù)利用和維護(hù)。

React的 Diff算法

react的diff算法用在什么地方呢勾习?當(dāng)組件更新的時(shí)候浓瞪,react會創(chuàng)建一個(gè)新的虛擬dom樹并且會和之前儲存的dom樹進(jìn)行比較,這個(gè)比較多過程就用到了diff算法巧婶,所以組件初始化的時(shí)候是用不到的乾颁。react提出了一種假設(shè),相同的節(jié)點(diǎn)具有類似的結(jié)構(gòu)艺栈,而不同的節(jié)點(diǎn)具有不同的結(jié)構(gòu)英岭。在這種假設(shè)之上進(jìn)行逐層的比較,如果發(fā)現(xiàn)對應(yīng)的節(jié)點(diǎn)是不同的湿右,那就直接刪除舊的節(jié)點(diǎn)以及它所包含的所有子節(jié)點(diǎn)然后替換成新的節(jié)點(diǎn)诅妹。如果是相同的節(jié)點(diǎn),則只進(jìn)行屬性的更改毅人。

對于列表的diff算法稍有不同吭狡,因?yàn)榱斜硗ǔ>哂邢嗤慕Y(jié)構(gòu),在對列表節(jié)點(diǎn)進(jìn)行刪除丈莺,插入划煮,排序的時(shí)候,單個(gè)節(jié)點(diǎn)的整體操作遠(yuǎn)比一個(gè)個(gè)對比一個(gè)個(gè)替換要好得多缔俄,所以在創(chuàng)建列表的時(shí)候需要設(shè)置key值弛秋,這樣react才能分清誰是誰。當(dāng)然不寫key值也可以牵现,但這樣通常會報(bào)出警告铐懊,通知我們加上key值以提高react的性能。

React組件是怎么來的

組件的創(chuàng)造方法為React.createClass() ——創(chuàng)造一個(gè)類瞎疼,react系統(tǒng)內(nèi)部設(shè)計(jì)了一套類系統(tǒng)科乎,利用它來創(chuàng)造react組件。但這并不是必須的贼急,我們還可以用es6的class類來創(chuàng)造組件,這也是Facebook官方推薦的寫法茅茂。

這兩種寫法實(shí)現(xiàn)的功能一樣但是原理卻是不同,es6的class類可以看作是構(gòu)造函數(shù)的一個(gè)語法糖太抓,可以把它當(dāng)成構(gòu)造函數(shù)來看空闲,extends實(shí)現(xiàn)了類之間的繼承 —— 定義一個(gè)類Main 繼承React.Component所有的屬性和方法,組件的生命周期函數(shù)就是從這來的走敌。constructor是構(gòu)造器碴倾,在實(shí)例化對象時(shí)調(diào)用,super調(diào)用了父類的constructor創(chuàng)造了父類的實(shí)例對象this,然后用子類的構(gòu)造函數(shù)進(jìn)行修改跌榔。這和es5的原型繼承是不同的异雁,原型繼承是先創(chuàng)造一個(gè)實(shí)例化對象this,然后再繼承父級的原型方法僧须。了解了這些之后我們在看組件的時(shí)候就清楚很多纲刀。

當(dāng)我們使用組件< Main />時(shí),其實(shí)是對Main類的實(shí)例化——new Main担平,只不過react對這個(gè)過程進(jìn)行了封裝示绊,讓它看起來更像是一個(gè)標(biāo)簽。

有三點(diǎn)值得注意:1暂论、定義類名字的首字母必須大寫 2面褐、因?yàn)閏lass變成了關(guān)鍵字,類選擇器需要用className來代替取胎。 3盆耽、類和模塊內(nèi)部默認(rèn)使用嚴(yán)格模式,所以不需要用use strict指定運(yùn)行模式扼菠。

組件的生命周期

組件在初始化時(shí)會觸發(fā)5個(gè)鉤子函數(shù):

1摄杂、getDefaultProps()

設(shè)置默認(rèn)的props,也可以用dufaultProps設(shè)置組件的默認(rèn)屬性循榆。

2析恢、getInitialState()

在使用es6的class語法時(shí)是沒有這個(gè)鉤子函數(shù)的,可以直接在constructor中定義this.state秧饮。此時(shí)可以訪問this.props映挂。

3、componentWillMount()

組件初始化時(shí)只調(diào)用盗尸,以后組件更新不調(diào)用柑船,整個(gè)生命周期只調(diào)用一次,此時(shí)可以修改state泼各。

4鞍时、 render()

react最重要的步驟,創(chuàng)建虛擬dom扣蜻,進(jìn)行diff算法逆巍,更新dom樹都在此進(jìn)行。此時(shí)就不能更改state了莽使。

5锐极、componentDidMount()

組件渲染之后調(diào)用,可以通過this.getDOMNode()獲取和操作dom節(jié)點(diǎn)芳肌,只調(diào)用一次灵再。

在更新時(shí)也會觸發(fā)5個(gè)鉤子函數(shù):

6肋层、componentWillReceivePorps(nextProps)

組件初始化時(shí)不調(diào)用,組件接受新的props時(shí)調(diào)用翎迁。

7槽驶、shouldComponentUpdate(nextProps, nextState)

react性能優(yōu)化非常重要的一環(huán)。組件接受新的state或者props時(shí)調(diào)用鸳兽,我們可以設(shè)置在此對比前后兩個(gè)props和state是否相同,如果相同則返回false阻止更新罕拂,因?yàn)橄嗤膶傩誀顟B(tài)一定會生成相同的dom樹揍异,這樣就不需要創(chuàng)造新的dom樹和舊的dom樹進(jìn)行diff算法對比,節(jié)省大量性能爆班,尤其是在dom結(jié)構(gòu)復(fù)雜的時(shí)候衷掷。不過調(diào)用this.forceUpdate會跳過此步驟。

8柿菩、componentWillUpdata(nextProps, nextState)

組件初始化時(shí)不調(diào)用戚嗅,只有在組件將要更新時(shí)才調(diào)用,此時(shí)可以修改state

9枢舶、render()

不多說

10懦胞、componentDidUpdate()

組件初始化時(shí)不調(diào)用,組件更新完成后調(diào)用凉泄,此時(shí)可以獲取dom節(jié)點(diǎn)躏尉。

還有一個(gè)卸載鉤子函數(shù)

11、componentWillUnmount()

組件將要卸載時(shí)調(diào)用后众,一些事件監(jiān)聽和定時(shí)器需要在此時(shí)清除胀糜。

以上可以看出來react總共有10個(gè)周期函數(shù)(render重復(fù)一次),這個(gè)10個(gè)函數(shù)可以滿足我們所有對組件操作的需求蒂誉,利用的好可以提高開發(fā)效率和組件性能教藻。

React-Router路由

Router就是React的一個(gè)組件,它并不會被渲染右锨,只是一個(gè)創(chuàng)建內(nèi)部路由規(guī)則的配置對象括堤,根據(jù)匹配的路由地址展現(xiàn)相應(yīng)的組件。Route則對路由地址和組件進(jìn)行綁定绍移,Route具有嵌套功能痊臭,表示路由地址的包涵關(guān)系,這和組件之間的嵌套并沒有直接聯(lián)系登夫。Route可以向綁定的組件傳遞7個(gè)屬性:children广匙,history,location恼策,params鸦致,route潮剪,routeParams,routes分唾,每個(gè)屬性都包涵路由的相關(guān)的信息抗碰。比較常用的有children(以路由的包涵關(guān)系為區(qū)分的組件),location(包括地址绽乔,參數(shù)弧蝇,地址切換方式,key值折砸,hash值)看疗。react-router提供Link標(biāo)簽,這只是對a標(biāo)簽的封裝睦授,值得注意的是帅涂,點(diǎn)擊鏈接進(jìn)行的跳轉(zhuǎn)并不是默認(rèn)的方式曙咽,react-router阻止了a標(biāo)簽的默認(rèn)行為并用pushState進(jìn)行hash值的轉(zhuǎn)變袍祖。切換頁面的過程是在點(diǎn)擊Link標(biāo)簽或者后退前進(jìn)按鈕時(shí)邪码,會先發(fā)生url地址的轉(zhuǎn)變,Router監(jiān)聽到地址的改變根據(jù)Route的path屬性匹配到對應(yīng)的組件删顶,將state值改成對應(yīng)的組件并調(diào)用setState觸發(fā)render函數(shù)重新渲染dom竖螃。

當(dāng)頁面比較多時(shí),項(xiàng)目就會變得越來越大逗余,尤其對于單頁面應(yīng)用來說斑鼻,初次渲染的速度就會很慢,這時(shí)候就需要按需加載猎荠,只有切換到頁面的時(shí)候才去加載對應(yīng)的js文件坚弱。react配合webpack進(jìn)行按需加載的方法很簡單,Route的component改為getComponent关摇,組件用require.ensure的方式獲取荒叶,并在webpack中配置chunkFilename。

組件之間的通信

react推崇的是單向數(shù)據(jù)流输虱,自上而下進(jìn)行數(shù)據(jù)的傳遞些楣,但是由下而上或者不在一條數(shù)據(jù)流上的組件之間的通信就會變的復(fù)雜。解決通信問題的方法很多宪睹,如果只是父子級關(guān)系愁茁,父級可以將一個(gè)回調(diào)函數(shù)當(dāng)作屬性傳遞給子級,子級可以直接調(diào)用函數(shù)從而和父級通信亭病。

組件層級嵌套到比較深鹅很,可以使用上下文getChildContext來傳遞信息,這樣在不需要將函數(shù)一層層往下傳罪帖,任何一層的子級都可以通過this.context直接訪問促煮。

兄弟關(guān)系的組件之間無法直接通信邮屁,它們只能利用同一層的上級作為中轉(zhuǎn)站。而如果兄弟組件都是最高層的組件菠齿,為了能夠讓它們進(jìn)行通信佑吝,必須在它們外層再套一層組件,這個(gè)外層的組件起著保存數(shù)據(jù)绳匀,傳遞信息的作用芋忿,這其實(shí)就是redux所做的事情。

組件之間的信息還可以通過全局事件來傳遞疾棵。不同頁面可以通過參數(shù)傳遞數(shù)據(jù)戈钢,下個(gè)頁面可以用location.param來獲取。其實(shí)react本身很簡單陋桂,難的在于如何優(yōu)雅高效的實(shí)現(xiàn)組件之間數(shù)據(jù)的交流。

Redux

首先蝶溶,redux并不是必須的嗜历,它的作用相當(dāng)于在頂層組件之上又加了一個(gè)組件,作用是進(jìn)行邏輯運(yùn)算抖所、儲存數(shù)據(jù)和實(shí)現(xiàn)組件尤其是頂層組件的通信梨州。如果組件之間的交流不多,邏輯不復(fù)雜田轧,只是單純的進(jìn)行視圖的渲染暴匠,這時(shí)候用回調(diào),context就行傻粘,沒必要用redux每窖,用了反而影響開發(fā)速度。但是如果組件交流特別頻繁弦悉,邏輯很復(fù)雜窒典,那redux的優(yōu)勢就特別明顯了。我第一次做react項(xiàng)目的時(shí)候并沒有用redux稽莉,所有的邏輯都是在組件內(nèi)部實(shí)現(xiàn)瀑志,當(dāng)時(shí)為了實(shí)現(xiàn)一個(gè)邏輯比較復(fù)雜的購物車,洋洋灑灑居然寫了800多行代碼污秆,回頭一看我自己都不知道寫的是啥劈猪,畫面太感人。

先簡單說一下redux和react是怎么配合的良拼。react-redux提供了connect和Provider兩個(gè)好基友战得,它們一個(gè)將組件與redux關(guān)聯(lián)起來,一個(gè)將store傳給組件庸推。組件通過dispatch發(fā)出action贡避,store根據(jù)action的type屬性調(diào)用對應(yīng)的reducer并傳入state和這個(gè)action痛黎,reducer對state進(jìn)行處理并返回一個(gè)新的state放入store,connect監(jiān)聽到store發(fā)生變化刮吧,調(diào)用setState更新組件湖饱,此時(shí)組件的props也就跟著變化。

流程是這個(gè)樣子的:

值得注意的是connect杀捻,Provider井厌,mapStateToProps,mapDispatchToProps是react-redux提供的,redux本身和react沒有半毛錢關(guān)系致讥,它只是數(shù)據(jù)處理中心仅仆,沒有和react產(chǎn)生任何耦合,是react-redux讓它們聯(lián)系在一起垢袱。

接下來具體分析一下墓拜,redux以及react-redux到底是怎么實(shí)現(xiàn)的。

給大家看一張圖片吧

明顯比第一張要復(fù)雜请契,其實(shí)兩張圖說的是同一件事咳榜。從上而下慢慢分析:

說說redux:

redux主要由三部分組成:store,reducer爽锥,action涌韩。

store是一個(gè)對象,它有四個(gè)主要的方法:

1氯夷、dispatch:

用于action的分發(fā)——在createStore中可以用middleware中間件對dispatch進(jìn)行改造臣樱,比如當(dāng)action傳入dispatch會立即觸發(fā)reducer,有些時(shí)候我們不希望它立即觸發(fā)腮考,而是等待異步操作完成之后再觸發(fā)雇毫,這時(shí)候用redux-thunk對dispatch進(jìn)行改造,以前只能傳入一個(gè)對象踩蔚,改造完成后可以傳入一個(gè)函數(shù)嘴拢,在這個(gè)函數(shù)里我們手動dispatch一個(gè)action對象,這個(gè)過程是可控的寂纪,就實(shí)現(xiàn)了異步席吴。

2、subscribe:

監(jiān)聽state的變化——這個(gè)函數(shù)在store調(diào)用dispatch時(shí)會注冊一個(gè)listener監(jiān)聽state變化捞蛋,當(dāng)我們需要知道state是否變化時(shí)可以調(diào)用孝冒,它返回一個(gè)函數(shù),調(diào)用這個(gè)返回的函數(shù)可以注銷監(jiān)聽拟杉。

let unsubscribe = store.subscribe(() => {console.log(‘state發(fā)生了變化’)})

3庄涡、getState:

獲取store中的state——當(dāng)我們用action觸發(fā)reducer改變了state時(shí),需要再拿到新的state里的數(shù)據(jù)搬设,畢竟數(shù)據(jù)才是我們想要的穴店。getState主要在兩個(gè)地方需要用到撕捍,一是在dispatch拿到action后store需要用它來獲取state里的數(shù)據(jù),并把這個(gè)數(shù)據(jù)傳給reducer泣洞,這個(gè)過程是自動執(zhí)行的忧风,二是在我們利用subscribe監(jiān)聽到state發(fā)生變化后調(diào)用它來獲取新的state數(shù)據(jù),如果做到這一步球凰,說明我們已經(jīng)成功了狮腿。

4、replaceReducer:

替換reducer呕诉,改變state修改的邏輯缘厢。

store可以通過createStore()方法創(chuàng)建,接受三個(gè)參數(shù)甩挫,經(jīng)過combineReducers合并的reducer和state的初始狀態(tài)以及改變dispatch的中間件贴硫,后兩個(gè)參數(shù)并不是必須的。store的主要作用是將action和reducer聯(lián)系起來并改變state伊者。

action:

action是一個(gè)對象英遭,其中type屬性是必須的,同時(shí)可以傳入一些數(shù)據(jù)删壮。action可以用actionCreactor進(jìn)行創(chuàng)造贪绘。dispatch就是把a(bǔ)ction對象發(fā)送出去兑牡。

reducer:

reducer是一個(gè)函數(shù)央碟,它接受一個(gè)state和一個(gè)action,根據(jù)action的type返回一個(gè)新的state均函。根據(jù)業(yè)務(wù)邏輯可以分為很多個(gè)reducer亿虽,然后通過combineReducers將它們合并,state樹中有很多對象苞也,每個(gè)state對象對應(yīng)一個(gè)reducer洛勉,state對象的名字可以在合并時(shí)定義。

像這個(gè)樣子:

const reducer = combineReducers({? ? a:doSomethingWithA,? ? b:processB,? ? c:c})

combineReducers:

其實(shí)它也是一個(gè)reducer如迟,它接受整個(gè)state和一個(gè)action收毫,然后將整個(gè)state拆分發(fā)送給對應(yīng)的reducer進(jìn)行處理,所有的reducer會收到相同的action殷勘,不過它們會根據(jù)action的type進(jìn)行判斷此再,有這個(gè)type就進(jìn)行處理然后返回新的state,沒有就返回默認(rèn)值玲销,然后這些分散的state又會整合在一起返回一個(gè)新的state樹输拇。

接下來分析一下整體的流程,首先調(diào)用store.dispatch將action作為參數(shù)傳入贤斜,同時(shí)用getState獲取當(dāng)前的狀態(tài)樹state并注冊subscribe的listener監(jiān)聽state變化策吠,再調(diào)用combineReducers并將獲取的state和action傳入逛裤。combineReducers會將傳入的state和action傳給所有reducer,reducer會根據(jù)state的key值獲取與自己對應(yīng)的state猴抹,并根據(jù)action的type返回新的state带族,觸發(fā)state樹的更新,我們調(diào)用subscribe監(jiān)聽到state發(fā)生變化后用getState獲取新的state數(shù)據(jù)洽糟。

redux的state和react的state兩者完全沒有關(guān)系炉菲,除了名字一樣。

上面分析了redux的主要功能坤溃,那么react-redux到底做了什么拍霜?

React-Redux

如果只使用redux,那么流程是這樣的:

component –> dispatch(action) –> reducer –> subscribe –> getState –> component

用了react-redux之后流程是這樣的:

component –> actionCreator(data) –> reducer –> component

store的三大功能:dispatch薪介,subscribe祠饺,getState都不需要手動來寫了。react-redux幫我們做了這些汁政,同時(shí)它提供了兩個(gè)好基友Provider和connect道偷。

Provider是一個(gè)組件,它接受store作為props记劈,然后通過context往下傳勺鸦,這樣react中任何組件都可以通過contex獲取store。也就意味著我們可以在任何一個(gè)組件里利用dispatch(action)來觸發(fā)reducer改變state目木,并用subscribe監(jiān)聽state的變化换途,然后用getState獲取變化后的值。但是并不推薦這樣做刽射,它會讓數(shù)據(jù)流變的混亂军拟,過度的耦合也會影響組件的復(fù)用,維護(hù)起來也更麻煩誓禁。

connect –connect(mapStateToProps, mapDispatchToProps, mergeProps, options)是一個(gè)函數(shù)懈息,它接受四個(gè)參數(shù)并且再返回一個(gè)函數(shù)–wrapWithConnect,wrapWithConnect接受一個(gè)組件作為參數(shù)wrapWithConnect(component)摹恰,它內(nèi)部定義一個(gè)新組件Connect(容器組件)并將傳入的組件(ui組件)作為Connect的子組件然后return出去辫继。

所以它的完整寫法是這樣的:connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)

mapStateToProps(state, [ownProps]):

mapStateToProps 接受兩個(gè)參數(shù),store的state和自定義的props俗慈,并返回一個(gè)新的對象姑宽,這個(gè)對象會作為props的一部分傳入ui組件。我們可以根據(jù)組件所需要的數(shù)據(jù)自定義返回一個(gè)對象姜盈。ownProps的變化也會觸發(fā)mapStateToProps

functionmapStateToProps(state){return{ todos: state.todos };}

mapDispatchToProps(dispatch, [ownProps]):

mapDispatchToProps如果是對象低千,那么會和store綁定作為props的一部分傳入ui組件。如果是個(gè)函數(shù),它接受兩個(gè)參數(shù)示血,bindActionCreators會將action和dispatch綁定并返回一個(gè)對象棋傍,這個(gè)對象會和ownProps一起作為props的一部分傳入ui組件。所以不論mapDispatchToProps是對象還是函數(shù)难审,它最終都會返回一個(gè)對象瘫拣,如果是函數(shù),這個(gè)對象的key值是可以自定義的

functionmapDispatchToProps(dispatch){return{? ? ? todoActions: bindActionCreators(todoActionCreators, dispatch),? ? ? counterActions: bindActionCreators(counterActionCreators, dispatch)? };}

mapDispatchToProps返回的對象其屬性其實(shí)就是一個(gè)個(gè)actionCreator告喊,因?yàn)橐呀?jīng)和dispatch綁定麸拄,所以當(dāng)調(diào)用actionCreator時(shí)會立即發(fā)送action,而不用手動dispatch黔姜。ownProps的變化也會觸發(fā)mapDispatchToProps拢切。

mergeProps(stateProps, dispatchProps, ownProps):

將mapStateToProps() 與 mapDispatchToProps()返回的對象和組件自身的props合并成新的props并傳入組件。默認(rèn)返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的結(jié)果秆吵。

options:

pure = true 表示Connect容器組件將在shouldComponentUpdate中對store的state和ownProps進(jìn)行淺對比淮椰,判斷是否發(fā)生變化,優(yōu)化性能纳寂。為false則不對比主穗。

其實(shí)connect函數(shù)并沒有做什么,大部分的邏輯都是在它返回的wrapWithConnect函數(shù)內(nèi)實(shí)現(xiàn)的毙芜,確切的說是在wrapWithConnect內(nèi)定義的Connect組件里實(shí)現(xiàn)的忽媒。

下面是一個(gè)完整的 react –> redux –> react 流程:

一、Provider組件接受redux的store作為props腋粥,然后通過context往下傳晦雨。

二、connect函數(shù)在初始化的時(shí)候會將mapDispatchToProps對象綁定到store灯抛,如果mapDispatchToProps是函數(shù)則在Connect組件獲得store后金赦,根據(jù)傳入的store.dispatch和action通過bindActionCreators進(jìn)行綁定音瓷,再將返回的對象綁定到store对嚼,connect函數(shù)會返回一個(gè)wrapWithConnect函數(shù),同時(shí)wrapWithConnect會被調(diào)用且傳入一個(gè)ui組件绳慎,wrapWithConnect內(nèi)部使用class Connect extends Component定義了一個(gè)Connect組件纵竖,傳入的ui組件就是Connect的子組件,然后Connect組件會通過context獲得store杏愤,并通過store.getState獲得完整的state對象靡砌,將state傳入mapStateToProps返回stateProps對象、mapDispatchToProps對象或mapDispatchToProps函數(shù)會返回一個(gè)dispatchProps對象珊楼,stateProps通殃、dispatchProps以及Connect組件的props三者通過Object.assign(),或者mergeProps合并為props傳入ui組件。然后在ComponentDidMount中調(diào)用store.subscribe画舌,注冊了一個(gè)回調(diào)函數(shù)handleChange監(jiān)聽state的變化堕担。

三、此時(shí)ui組件就可以在props中找到actionCreator曲聂,當(dāng)我們調(diào)用actionCreator時(shí)會自動調(diào)用dispatch霹购,在dispatch中會調(diào)用getState獲取整個(gè)state,同時(shí)注冊一個(gè)listener監(jiān)聽state的變化朋腋,store將獲得的state和action傳給combineReducers齐疙,combineReducers會將state依據(jù)state的key值分別傳給子reducer,并將action傳給全部子reducer旭咽,reducer會被依次執(zhí)行進(jìn)行action.type的判斷贞奋,如果有則返回一個(gè)新的state,如果沒有則返回默認(rèn)穷绵。combineReducers再次將子reducer返回的單個(gè)state進(jìn)行合并成一個(gè)新的完整的state忆矛。此時(shí)state發(fā)生了變化。Connect組件中調(diào)用的subscribe會監(jiān)聽到state發(fā)生了變化请垛,然后調(diào)用handleChange函數(shù)催训,handleChange函數(shù)內(nèi)部首先調(diào)用getState獲取新的state值并對新舊兩個(gè)state進(jìn)行淺對比,如果相同直接return宗收,如果不同則調(diào)用mapStateToProps獲取stateProps并將新舊兩個(gè)stateProps進(jìn)行淺對比漫拭,如果相同,直接return結(jié)束混稽,不進(jìn)行后續(xù)操作采驻。如果不相同則調(diào)用this.setState()觸發(fā)Connect組件的更新,傳入ui組件匈勋,觸發(fā)ui組件的更新礼旅,此時(shí)ui組件獲得新的props,react –> redux –> react 的一次流程結(jié)束洽洁。

上面的有點(diǎn)復(fù)雜痘系,簡化版的流程是:

一、Provider組件接受redux的store作為props饿自,然后通過context往下傳汰翠。

二、connect函數(shù)收到Provider傳出的store昭雌,然后接受三個(gè)參數(shù)mapStateToProps复唤,mapDispatchToProps和組件,并將state和actionCreator以props傳入組件烛卧,這時(shí)組件就可以調(diào)用actionCreator函數(shù)來觸發(fā)reducer函數(shù)返回新的state佛纫,connect監(jiān)聽到state變化調(diào)用setState更新組件并將新的state傳入組件。

connect可以寫的非常簡潔,mapStateToProps呈宇,mapDispatchToProps只不過是傳入的回調(diào)函數(shù)跟磨,connect函數(shù)在必要的時(shí)候會調(diào)用它們,名字不是固定的攒盈,甚至可以不寫名字抵拘。

簡化版本:

connect(state=> state, action)(Component);

項(xiàng)目搭建

上面說了react,react-router和redux的知識點(diǎn)型豁。但是怎么樣將它們整合起來僵蛛,搭建一個(gè)完整的項(xiàng)目。

1迎变、先引用 react.js充尉,redux,react-router 等基本文件衣形,建議用npm安裝驼侠,直接在文件中引用。

2谆吴、從 react.js倒源,redux,react-router 中引入所需要的對象和方法句狼。

importReact, {Component, PropTypes} from'react';importReactDOM, {render} from'react-dom';import{Provider, connect} from'react-redux';import{createStore, combineReducers, applyMiddleware} from'redux';import{ Router, Route, Redirect, IndexRoute, browserHistory, hashHistory } from'react-router';

3笋熬、根據(jù)需求創(chuàng)建頂層ui組件,每個(gè)頂層ui組件對應(yīng)一個(gè)頁面腻菇。

4胳螟、創(chuàng)建actionCreators和reducers,并用combineReducers將所有的reducer合并成一個(gè)大的reduer筹吐。利用createStore創(chuàng)建store并引入combineReducers和applyMiddleware糖耸。

5、利用connect將actionCreator丘薛,reuder和頂層的ui組件進(jìn)行關(guān)聯(lián)并返回一個(gè)新的組件嘉竟。

6、利用connect返回的新的組件配合react-router進(jìn)行路由的部署榔袋,返回一個(gè)路由組件Router周拐。

7铡俐、將Router放入最頂層組件Provider凰兑,引入store作為Provider的屬性。

8审丘、調(diào)用render渲染Provider組件且放入頁面的標(biāo)簽中吏够。

可以看到頂層的ui組件其實(shí)被套了四層組件,Provider,Router锅知,Route播急,Connect,這四個(gè)組件并不會在視圖上改變r(jià)eact售睹,它們只是功能性的桩警。

通常我們在頂層的ui組件打印props時(shí)可以看到一堆屬性:

上圖的頂層ui組件屬性總共有18個(gè),如果剛剛接觸react昌妹,可能對這些屬性怎么來的感到困惑捶枢,其實(shí)這些屬性來自五個(gè)地方:

組件自定義屬性1個(gè),actionCreator返回的對象6個(gè)飞崖,reducer返回的state4個(gè)烂叔,Connect組件屬性0個(gè),以及Router注入的屬性7個(gè)固歪。

此文章部分內(nèi)容來自其他大牛蒜鸡,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末牢裳,一起剝皮案震驚了整個(gè)濱河市逢防,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒲讯,老刑警劉巖胞四,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伶椿,居然都是意外死亡辜伟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門脊另,熙熙樓的掌柜王于貴愁眉苦臉地迎上來导狡,“玉大人,你說我怎么就攤上這事偎痛『蹬酰” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵踩麦,是天一觀的道長枚赡。 經(jīng)常有香客問我,道長谓谦,這世上最難降的妖魔是什么贫橙? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮反粥,結(jié)果婚禮上卢肃,老公的妹妹穿的比我還像新娘疲迂。我一直安慰自己,他們只是感情好莫湘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布尤蒿。 她就那樣靜靜地躺著,像睡著了一般幅垮。 火紅的嫁衣襯著肌膚如雪腰池。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天忙芒,我揣著相機(jī)與錄音巩螃,去河邊找鬼。 笑死匕争,一個(gè)胖子當(dāng)著我的面吹牛避乏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甘桑,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拍皮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了跑杭?” 一聲冷哼從身側(cè)響起铆帽,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎德谅,沒想到半個(gè)月后爹橱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窄做,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年愧驱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椭盏。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡组砚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掏颊,到底是詐尸還是另有隱情糟红,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布乌叶,位于F島的核電站盆偿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏准浴。R本人自食惡果不足惜事扭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兄裂。 院中可真熱鬧句旱,春花似錦阳藻、人聲如沸晰奖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匾南。三九已至啃匿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛆楞,已是汗流浹背溯乒。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豹爹,地道東北人裆悄。 一個(gè)月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像臂聋,于是被迫代替她去往敵國和親光稼。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

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