React-Redux是用在链接React和Redux上的。若是你想同时用这两个框架,那么React-Redux基本就是必须的了。为了可以更好的使用这个工具,今天就对它进行一下源码剖析。app
一个React组件,通常你的rootApp要放倒这个组件内部渲染。它很简单,最关键的做用就是在context中放入Redux的store,方便子组件获取。关键代码:框架
getChildContext() { return { store: this.store } } Provider.childContextTypes = { store: storeShape.isRequired }
这样connect的组件就能够获取store,使用store的方法。ide
首选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。性能
一个React组件ui
Connect.contextTypes = { store: storeShape }
因此它能够从context中获取Provider放的store。this
在constructor中:spa
//获取store this.store = props.store || context.store const storeState = this.store.getState() //把store的state做为组件的state,后面经过更新state更新组件 this.state = { storeState } //清除组件的状态,内部是一系列的标示还原 this.clearCache()
而后是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。
它内部的关键代码是:
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这个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,最终组件仍是不能经过这种方式更新。
下面假定触发了一次dispatch,这个时候handleChange就会执行,若是state没有发生改变,而且pure为true,就什么都不作直接返回,pure又在性能上立功了。若是state发生了改变会再作一些计算对比,好比计算this.stateProps。最后是在要更新的时候会:
this.hasStoreStateChanged = true this.setState({ storeState })
调用setState来触发组件更新。这里其实意味着只要store的state发生改变,全部的mapStateToProps、 mapDispatchToProps、mergeProps都会执行。
这个时候会调用它内部实现的shouldComponentUpdate,用来提升性能。
shouldComponentUpdate() { return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged }
可是怎么感受这个并无什么用呢?多是我理解不深,由于不管是父组件更新props仍是state改变这里老是返回true,而无论改变的是否是这个组件关心的数据。没办法又进入了render方法。
好了,源码剖析到此结束,谢谢观看!