React-Redux源碼剖析

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

Provider

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

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

Provider.childContextTypes = {
   store: storeShape.isRequired
}

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

connect

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

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

//mapDispatchToProps的處理,最后的情況實(shí)際是使用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ù)是個(gè)React組件:WrappedComponent,之后返回一個(gè)新的React組件Connect。

return hoistStatics(Connect, WrappedComponent)

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


一個(gè)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,后面通過(guò)更新state更新組件
this.state = { storeState }
//清除組件的狀態(tài),內(nèi)部是一系列的標(biāo)示還原
this.clearCache()

render

然后是render方法,在掛載的時(shí)候,會(huì)經(jīng)過(guò)一系列的判斷和計(jì)算,比如使用mapState計(jì)算nextStateProps,并和this.stateProps對(duì)比是否發(fā)生改變,如果發(fā)生改變:

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

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

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

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

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

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

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

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

componentDidMount

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

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

在不指定mapStateToProps的時(shí)候shouldSubscribe等于false,這就意味著React-Redux的源碼剖析到此結(jié)束,謝謝觀看!當(dāng)然如果指定了mapStateToProps剖析就還得繼續(xù)。看到代碼沒(méi)有,竟然使用subscribe,意味著只要執(zhí)行dispatch,handleChange就會(huì)執(zhí)行。至此組件已經(jīng)掛載完畢,后面的代碼執(zhí)行需要有外界因素了,比如父組件傳遞新的props、執(zhí)行dispatch。

componentWillReceiveProps

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

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

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

handleChange

下面假定觸發(fā)了一次dispatch,這個(gè)時(shí)候handleChange就會(huì)執(zhí)行,如果state沒(méi)有發(fā)生改變,并且pure為true,就什么都不做直接返回,pure又在性能上立功了。如果state發(fā)生了改變會(huì)再做一些計(jì)算對(duì)比,比如計(jì)算this.stateProps。最后是在要更新的時(shí)候會(huì):

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

調(diào)用setState來(lái)觸發(fā)組件更新。這里其實(shí)意味著只要store的state發(fā)生改變,所有的mapStateToProps、 mapDispatchToProps、mergeProps都會(huì)執(zhí)行。

shouldComponentUpdate

這個(gè)時(shí)候會(huì)調(diào)用它內(nèi)部實(shí)現(xiàn)的shouldComponentUpdate,用來(lái)提高性能。

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

但是怎么感覺(jué)這個(gè)并沒(méi)有什么用呢?可能是我理解不深,因?yàn)闊o(wú)論是父組件更新props還是state改變這里總是返回true,而不管改變的是不是這個(gè)組件關(guān)心的數(shù)據(jù)。沒(méi)辦法又進(jìn)入了render方法。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容