React-Redux源碼剖析

React-Redux是用在鏈接React和Redux上的。若是你想同時用這兩個框架,那麼React-Redux基本就是必須的了。爲了可以更好的使用這個工具,今天就對它進行一下源碼剖析。app

Provider

一個React組件,通常你的rootApp要放倒這個組件內部渲染。它很簡單,最關鍵的做用就是在context中放入Redux的store,方便子組件獲取。關鍵代碼:框架

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

Provider.childContextTypes = {
   store: storeShape.isRequired
}

這樣connect的組件就能夠獲取store,使用store的方法。ide

connect

首選connect是個能夠執行兩次的柯里化函數,第一次傳入的參數至關於一系列的定製化東西,第二次傳入的是你要鏈接的React組件,而後返回一個新的React組件。
第一次執行時傳入的參數是mapStateToProps, mapDispatchToProps, mergeProps, options這四個。首先會對這幾個參數進行處理,代碼以下:函數

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

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

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

第二次執行函數接收的參數是個React組件:WrappedComponent,以後返回一個新的React組件Connect。工具

return hoistStatics(Connect, WrappedComponent)

把WrappedComponent的非React屬性拷貝到Connect上。下面詳細說下Connect。性能

Connect

一個React組件ui

Connect.contextTypes = {
    store: storeShape
}

因此它能夠從context中獲取Provider放的store。this

constructor

在constructor中:spa

//獲取store
this.store = props.store || context.store
const storeState = this.store.getState()
//把store的state做爲組件的state,後面經過更新state更新組件
this.state = { storeState }
//清除組件的狀態,內部是一系列的標示還原
this.clearCache()

render

而後是render方法,在掛載的時候,會通過一系列的判斷和計算,好比使用mapState計算nextStateProps,並和this.stateProps對比是否發生改變,若是發生改變:code

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

使用mapDispatch計算nextDispatchProps,並和this.dispatchProps對比是否發生改變,若是發生改變:

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

若是上面的兩個對比有一個發生改變,就會繼續使用finalMergeProps來計算最終的數據合併結果nextMergedProps,並和this.mergedProps對比是否發生改變,若是發生改變:

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

若是上面的對比肯定發生改變

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。若是前面說的這些對比的結果都是false,就會直接返回this.renderedElement,組件不進行任何更新。固然組件掛載的時候前面的對比都會返回true。

componentDidMount

它內部的關鍵代碼是:

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

在不指定mapStateToProps的時候shouldSubscribe等於false,這就意味着React-Redux的源碼剖析到此結束,謝謝觀看!固然若是指定了mapStateToProps剖析就還得繼續。看到代碼沒有,居然使用subscribe,意味着只要執行dispatch,handleChange就會執行。至此組件已經掛載完畢,後面的代碼執行須要有外界因素了,好比父組件傳遞新的props、執行dispatch。

componentWillReceiveProps

組件還實現了componentWillReceiveProps這個React生命週期中的方法:

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

看到pure的重要性了吧,若是pure被設置爲false就意味着無論屬性是否淺相等this.haveOwnPropsChanged老是會被設置爲true,而這會致使後面一系列的爲了更新而進行的計算,因此pure爲true是能夠給你的性能帶來幫助的,不過它默認就是true。這裏設置this.haveOwnPropsChanged等於true是給經過直接經過父組件傳遞props更新組件帶來可能,固然須要配合mapStateToProps, mapDispatchToProps, mergeProps這三個函數,若是它們都沒有利用ownProps,最終組件仍是不能經過這種方式更新。

handleChange

下面假定觸發了一次dispatch,這個時候handleChange就會執行,若是state沒有發生改變,而且pure爲true,就什麼都不作直接返回,pure又在性能上立功了。若是state發生了改變會再作一些計算對比,好比計算this.stateProps。最後是在要更新的時候會:

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

調用setState來觸發組件更新。這裏其實意味着只要store的state發生改變,全部的mapStateToProps、 mapDispatchToProps、mergeProps都會執行。

shouldComponentUpdate

這個時候會調用它內部實現的shouldComponentUpdate,用來提升性能。

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

可是怎麼感受這個並無什麼用呢?多是我理解不深,由於不管是父組件更新props仍是state改變這裏老是返回true,而無論改變的是否是這個組件關心的數據。沒辦法又進入了render方法。

好了,源碼剖析到此結束,謝謝觀看!

相關文章
相關標籤/搜索