React-Redux源碼剖析

React-Redux是用在連接React和Redux上的。如果你想同時用這兩個框架吃引,那么React-Redux基本就是必須的了筹陵。為了能夠更好的使用這個工具,今天就對它進(jìn)行一下源碼剖析镊尺。

Provider

一個React組件朦佩,一般你的rootApp要放倒這個組件內(nèi)部渲染。它很簡單庐氮,最關(guān)鍵的作用就是在context中放入Redux的store语稠,方便子組件獲取。關(guān)鍵代碼:

getChildContext() {
    return { store: this.store }
}

Provider.childContextTypes = {
   store: storeShape.isRequired
}

這樣connect的組件就可以獲取store弄砍,使用store的方法仙畦。

connect

首選connect是個可以執(zhí)行兩次的柯里化函數(shù),第一次傳入的參數(shù)相當(dāng)于一系列的定制化東西输枯,第二次傳入的是你要連接的React組件议泵,然后返回一個新的React組件。
第一次執(zhí)行時傳入的參數(shù)是mapStateToProps, mapDispatchToProps, mergeProps, options這四個桃熄。首先會對這幾個參數(shù)進(jìn)行處理先口,代碼如下:

//決定組件會不會因state改變而更新
const shouldSubscribe = Boolean(mapStateToProps)
//如果不傳遞這個參數(shù)使用默認(rèn)state => ({})
const mapState = mapStateToProps || defaultMapStateToProps

//mapDispatchToProps的處理型奥,最后的情況實際是使用bindActionCreators處理
let mapDispatch
if (typeof mapDispatchToProps === 'function') {
    mapDispatch = mapDispatchToProps
} else if (!mapDispatchToProps) {
    mapDispatch = defaultMapDispatchToProps
} else {
    mapDispatch = wrapActionCreators(mapDispatchToProps)
}

//不傳遞就使用默認(rèn)值
const finalMergeProps = mergeProps || defaultMergeProps
const { pure = true, withRef = false } = options

第二次執(zhí)行函數(shù)接收的參數(shù)是個React組件:WrappedComponent,之后返回一個新的React組件Connect碉京。

return hoistStatics(Connect, WrappedComponent)

把WrappedComponent的非React屬性拷貝到Connect上厢汹。下面詳細(xì)說下Connect。
Connect


一個React組件

Connect.contextTypes = {
    store: storeShape
}

所以它可以從context中獲取Provider放的store谐宙。

constructor

在constructor中:

//獲取store
this.store = props.store || context.store
const storeState = this.store.getState()
//把store的state作為組件的state烫葬,后面通過更新state更新組件
this.state = { storeState }
//清除組件的狀態(tài),內(nèi)部是一系列的標(biāo)示還原
this.clearCache()

render

然后是render方法凡蜻,在掛載的時候搭综,會經(jīng)過一系列的判斷和計算,比如使用mapState計算nextStateProps划栓,并和this.stateProps對比是否發(fā)生改變兑巾,如果發(fā)生改變:

nextDispatchProps = mapState(store.getState(), [props])
this.stateProps = nextDispatchProps

使用mapDispatch計算nextDispatchProps,并和this.dispatchProps對比是否發(fā)生改變忠荞,如果發(fā)生改變:

nextMergedProps = mapDispatch(dispatch, [props])
this.dispatchProps = nextMergedProps

如果上面的兩個對比有一個發(fā)生改變蒋歌,就會繼續(xù)使用finalMergeProps來計算最終的數(shù)據(jù)合并結(jié)果nextMergedProps,并和this.mergedProps對比是否發(fā)生改變委煤,如果發(fā)生改變:

nextMergedProps = finalMergeProps(this.stateProps, this.dispatchProps, this.props)
this.mergedProps = nextMergedProps

如果上面的對比確定發(fā)生改變

if (withRef) {
  this.renderedElement = createElement(WrappedComponent, {
      ...this.mergedProps,
      ref: 'wrappedInstance'
  })
} else {
  this.renderedElement = createElement(WrappedComponent,
      this.mergedProps
  )
}
return this.renderedElement

如果withRef等于true就會增加ref屬性堂油,然后可以通過getWrappedInstance方法獲取DOM。如果前面說的這些對比的結(jié)果都是false碧绞,就會直接返回this.renderedElement府框,組件不進(jìn)行任何更新。當(dāng)然組件掛載的時候前面的對比都會返回true头遭。

componentDidMount

它內(nèi)部的關(guān)鍵代碼是:

if (shouldSubscribe && !this.unsubscribe) {
    this.unsubscribe = this.store.subscribe(this.handleChange.bind(this))
    this.handleChange()
}

在不指定mapStateToProps的時候shouldSubscribe等于false寓免,這就意味著React-Redux的源碼剖析到此結(jié)束癣诱,謝謝觀看计维!當(dāng)然如果指定了mapStateToProps剖析就還得繼續(xù)∷河瑁看到代碼沒有鲫惶,竟然使用subscribe,意味著只要執(zhí)行dispatch实抡,handleChange就會執(zhí)行欠母。至此組件已經(jīng)掛載完畢,后面的代碼執(zhí)行需要有外界因素了吆寨,比如父組件傳遞新的props赏淌、執(zhí)行dispatch。

componentWillReceiveProps

組件還實現(xiàn)了componentWillReceiveProps這個React生命周期中的方法:

componentWillReceiveProps(nextProps) {
    if (!pure || !shallowEqual(nextProps, this.props)) {
        this.haveOwnPropsChanged = true
    }
}

看到pure的重要性了吧啄清,如果pure被設(shè)置為false就意味著不管屬性是否淺相等this.haveOwnPropsChanged總是會被設(shè)置為true六水,而這會導(dǎo)致后面一系列的為了更新而進(jìn)行的計算,所以pure為true是可以給你的性能帶來幫助的,不過它默認(rèn)就是true掷贾。這里設(shè)置this.haveOwnPropsChanged等于true是給通過直接通過父組件傳遞props更新組件帶來可能睛榄,當(dāng)然需要配合mapStateToProps, mapDispatchToProps, mergeProps這三個函數(shù),如果它們都沒有利用ownProps想帅,最終組件還是不能通過這種方式更新场靴。

handleChange

下面假定觸發(fā)了一次dispatch,這個時候handleChange就會執(zhí)行港准,如果state沒有發(fā)生改變旨剥,并且pure為true,就什么都不做直接返回浅缸,pure又在性能上立功了泞边。如果state發(fā)生了改變會再做一些計算對比,比如計算this.stateProps疗杉。最后是在要更新的時候會:

this.hasStoreStateChanged = true
this.setState({ storeState })

調(diào)用setState來觸發(fā)組件更新阵谚。這里其實意味著只要store的state發(fā)生改變,所有的mapStateToProps烟具、 mapDispatchToProps梢什、mergeProps都會執(zhí)行。

shouldComponentUpdate

這個時候會調(diào)用它內(nèi)部實現(xiàn)的shouldComponentUpdate朝聋,用來提高性能嗡午。

shouldComponentUpdate() {
    return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged
}

但是怎么感覺這個并沒有什么用呢?可能是我理解不深冀痕,因為無論是父組件更新props還是state改變這里總是返回true荔睹,而不管改變的是不是這個組件關(guān)心的數(shù)據(jù)。沒辦法又進(jìn)入了render方法言蛇。

好了僻他,源碼剖析到此結(jié)束,謝謝觀看腊尚!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吨拗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子婿斥,更是在濱河造成了極大的恐慌劝篷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件民宿,死亡現(xiàn)場離奇詭異娇妓,居然都是意外死亡,警方通過查閱死者的電腦和手機活鹰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門哈恰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坟桅,“玉大人,你說我怎么就攤上這事蕊蝗〗雠遥” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵蓬戚,是天一觀的道長夸楣。 經(jīng)常有香客問我,道長子漩,這世上最難降的妖魔是什么豫喧? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮幢泼,結(jié)果婚禮上紧显,老公的妹妹穿的比我還像新娘。我一直安慰自己缕棵,他們只是感情好孵班,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著招驴,像睡著了一般篙程。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上别厘,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天虱饿,我揣著相機與錄音,去河邊找鬼触趴。 笑死氮发,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冗懦。 我是一名探鬼主播爽冕,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼批狐!你這毒婦竟也來了扇售?” 一聲冷哼從身側(cè)響起前塔,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤嚣艇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后华弓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體食零,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年寂屏,在試婚紗的時候發(fā)現(xiàn)自己被綠了贰谣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娜搂。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吱抚,靈堂內(nèi)的尸體忽然破棺而出百宇,到底是詐尸還是另有隱情,我是刑警寧澤秘豹,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布携御,位于F島的核電站,受9級特大地震影響既绕,放射性物質(zhì)發(fā)生泄漏啄刹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一凄贩、第九天 我趴在偏房一處隱蔽的房頂上張望誓军。 院中可真熱鬧,春花似錦疲扎、人聲如沸昵时。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽债查。三九已至,卻和暖如春瓜挽,著一層夾襖步出監(jiān)牢的瞬間盹廷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工久橙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俄占,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓淆衷,卻偏偏與公主長得像缸榄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子祝拯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

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

  • 做React需要會什么佳头? react的功能其實很單一鹰贵,主要負(fù)責(zé)渲染的功能,現(xiàn)有的框架康嘉,比如angular是一個大而...
    蒼都閱讀 14,740評論 1 139
  • 前言 本文 有配套視頻碉输,可以酌情觀看。 文中內(nèi)容因各人理解不同亭珍,可能會有所偏差敷钾,歡迎朋友們聯(lián)系我討論枝哄。 文中所有內(nèi)...
    珍此良辰閱讀 11,894評論 23 111
  • 今天來看一下react組件之間是怎么進(jìn)行通訊的。react推崇的是單向數(shù)據(jù)流阻荒,自上而下進(jìn)行數(shù)據(jù)的傳遞挠锥,但是由下而上...
    親親qin閱讀 5,997評論 2 12
  • 英文文檔鏈接 API <Provider store> 使得層級之下的組件可以通過connect()函數(shù)訪問到Re...
    txwslyf閱讀 1,481評論 0 0
  • 一、什么情況需要redux侨赡? 1瘪贱、用戶的使用方式復(fù)雜 2、不同身份的用戶有不同的使用方式(比如普通用戶和管...
    初晨的筆記閱讀 2,013評論 0 11