正式学习React(五) react-redux源码分析

时间:2022-09-25 10:55:10

磨刀不误砍柴工,咱先把react-redux里的工具函数分析一下:

源码点这里

正式学习React(五) react-redux源码分析

 shallowEqual.js

 export default function shallowEqual(objA, objB) {
if (objA === objB) {
return true
} const keysA = Object.keys(objA)
const keysB = Object.keys(objB) if (keysA.length !== keysB.length) {
return false
} // Test for A's keys different from B.
const hasOwn = Object.prototype.hasOwnProperty
for (let i = 0; i < keysA.length; i++) {
if (!hasOwn.call(objB, keysA[i]) ||
objA[keysA[i]] !== objB[keysA[i]]) {
return false
}
} return true
}

这个几个api全都超级简单,我就不仔细讲解了,顾名思义,简单比较一下两个obj是否相等。

storeShape.js

 import { PropTypes } from 'react'

 export default PropTypes.shape({
subscribe: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
getState: PropTypes.func.isRequired
})

顾名思义,强制性规定subscribe,dispacth,getState必须是func.

warning.js

 /**
* Prints a warning in the console if it exists.
*
* @param {String} message The warning message.
* @returns {void}
*/
export default function warning(message) {
/* eslint-disable no-console */
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(message)
}
/* eslint-enable no-console */
try {
// This error was thrown as a convenience so that if you enable
// "break on all exceptions" in your console,
// it would pause the execution at this line.
throw new Error(message)
/* eslint-disable no-empty */
} catch (e) {}
/* eslint-enable no-empty */
}

就是用console.error 打印一下错误。

wrapActionCreators.js

 import { bindActionCreators } from 'redux'

 export default function wrapActionCreators(actionCreators) {
return dispatch => bindActionCreators(actionCreators, dispatch)
}

上一篇讲过 bindActionCreators


它返回的这个对象直接是以 我们定义单个actionCreator为key的,actionCreator函数为value的包装,并在actionCreator里挂着了dispacth的函数。使用的时候,直接调用同名key函数,就直接分发action了,不需要

我们手动的 dispacth(actionCreator(内容)), 直接key(内容) 就行了。

------------------------------------------------------工具全部介绍完毕-----是不是so easy??!!!------------------------------

 现在主角登场:

正式学习React(五) react-redux源码分析

Provider.js

 import { Component, PropTypes, Children } from 'react'
import storeShape from '../utils/storeShape'
import warning from '../utils/warning' let didWarnAboutReceivingStore = false
function warnAboutReceivingStore() {
if (didWarnAboutReceivingStore) {
return
}
didWarnAboutReceivingStore = true warning(
'<Provider> does not support changing `store` on the fly. ' +
'It is most likely that you see this error because you updated to ' +
'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' +
'automatically. See https://github.com/reactjs/react-redux/releases/' +
'tag/v2.0.0 for the migration instructions.'
)
} export default class Provider extends Component { //关键部分,将this.store加到了context里,这里,子组件就可以通过context直接拿到store,不需要一级一级props传递下去。
getChildContext() {
return { store: this.store }
} constructor(props, context) {
super(props, context)
this.store = props.store
} render() {
return Children.only(this.props.children)
}
} if (process.env.NODE_ENV !== 'production') {
Provider.prototype.componentWillReceiveProps = function (nextProps) {
const { store } = this
const { store: nextStore } = nextProps if (store !== nextStore) {
warnAboutReceivingStore()
}
}
} Provider.propTypes = {
//要求我们的 store对象里面的3个必须是func
store: storeShape.isRequired, //要求我们形如这种格式的 <Provider store={store}> <App/> </Provider> ,<App>必须是react的element,其实它还要求了只能是放单element的,这也是render这个本身限定的!!可以看上面的Children.Only()
children: PropTypes.element.isRequired
}
// 这个是和getChildContext一样,必须加的。 //访问context 的属性是需要通过 contextTypes 指定可访问的 元素一样。getChildContext 指定的传递给子组件的属性需要先通过 childContextTypes 来指定,不然会产生错误。
Provider.childContextTypes = {
store: storeShape.isRequired
}

关于context的用法,我在github上写了一个小demo。大家可以clone下来跑一跑,在我的代码基础上可以添加一下状态函数,看看react的状态生命周期的流程。点这里

对于上面的代码总结一下,Provider这个React 组件就是为了将Store挂在到Context中,然后我们写的真正的app里就可以获得store了。

 connect.js


分析之前,我們心中要有這麽一個概念:

<Provider store={store}>
<App />
</Provider>, Provider的作用就是將 store挂在到 context上 提供App使用。 重點在這个 App上。 -----------------------------------------------------------------------------------------------------
这个App不是普通的element。它经过connect包装过,
connect(select)(App)

好了,可以开始分析了,我们将知道connect是啥,select是干嘛的?

------------------------------------------------------------------------------------------------

 import { Component, createElement } from 'react'
import storeShape from '../utils/storeShape'
import shallowEqual from '../utils/shallowEqual'
import wrapActionCreators from '../utils/wrapActionCreators'
import warning from '../utils/warning'
import isPlainObject from 'lodash/isPlainObject'
import hoistStatics from 'hoist-non-react-statics'
import invariant from 'invariant' //一直到return 我都认为是废话,函数名字都是顾名思义的。。直接忽略。。。。
const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars
const defaultMapDispatchToProps = dispatch => ({ dispatch })
const defaultMergeProps = (stateProps, dispatchProps, parentProps) => ({
...parentProps,
...stateProps,
...dispatchProps
}) function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
} let errorObject = { value: null }
function tryCatch(fn, ctx) {
try {
return fn.apply(ctx)
} catch (e) {
errorObject.value = e
return errorObject
}
} // 重点开始了。。。。。。
// Helps track hot reloading.
let nextVersion = 0 export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) { //这里是否应该被订阅?嗯哼,回想一下store里的 subcribe,每次被dispacth 的时候就会执行!!!,这里估计就是给一个标志,
//如果传了mapStateToProps,必然是true,反之是false;
const shouldSubscribe = Boolean(mapStateToProps)

const mapState = mapStateToProps || defaultMapStateToProps 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
const checkMergedEquals = pure && finalMergeProps !== defaultMergeProps // Helps track hot reloading.
const version = nextVersion++ return function wrapWithConnect(WrappedComponent) { // 如果沒有為app添加disPlayName 或者 name 返回 "Conponent"
const connectDisplayName = `Connect(${getDisplayName(WrappedComponent)})` function checkStateShape(props, methodName) {
if (!isPlainObject(props)) {
warning(
`${methodName}() in ${connectDisplayName} must return a plain object. ` +
`Instead received ${props}.`
)
}
} function computeMergedProps(stateProps, dispatchProps, parentProps) {
const mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps)
if (process.env.NODE_ENV !== 'production') {
checkStateShape(mergedProps, 'mergeProps')
}
return mergedProps
} class Connect extends Component {
shouldComponentUpdate() {
return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged
} constructor(props, context) {
super(props, context)
this.version = version
this.store = props.store || context.store invariant(this.store,
`Could not find "store" in either the context or ` +
`props of "${connectDisplayName}". ` +
`Either wrap the root component in a <Provider>, ` +
`or explicitly pass "store" as a prop to "${connectDisplayName}".`
) const storeState = this.store.getState()
this.state = { storeState }
this.clearCache()
} computeStateProps(store, props) {
if (!this.finalMapStateToProps) {
return this.configureFinalMapState(store, props)
} const state = store.getState()
const stateProps = this.doStatePropsDependOnOwnProps ?
this.finalMapStateToProps(state, props) :
this.finalMapStateToProps(state) if (process.env.NODE_ENV !== 'production') {
checkStateShape(stateProps, 'mapStateToProps')
}
return stateProps
} configureFinalMapState(store, props) {
const mappedState = mapState(store.getState(), props)
const isFactory = typeof mappedState === 'function' this.finalMapStateToProps = isFactory ? mappedState : mapState
this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1 if (isFactory) {
return this.computeStateProps(store, props)
} if (process.env.NODE_ENV !== 'production') {
checkStateShape(mappedState, 'mapStateToProps')
}
return mappedState
} computeDispatchProps(store, props) {
if (!this.finalMapDispatchToProps) {
return this.configureFinalMapDispatch(store, props)
} const { dispatch } = store
const dispatchProps = this.doDispatchPropsDependOnOwnProps ?
this.finalMapDispatchToProps(dispatch, props) :
this.finalMapDispatchToProps(dispatch) if (process.env.NODE_ENV !== 'production') {
checkStateShape(dispatchProps, 'mapDispatchToProps')
}
return dispatchProps
} configureFinalMapDispatch(store, props) {
const mappedDispatch = mapDispatch(store.dispatch, props)
const isFactory = typeof mappedDispatch === 'function' this.finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch
this.doDispatchPropsDependOnOwnProps = this.finalMapDispatchToProps.length !== 1 if (isFactory) {
return this.computeDispatchProps(store, props)
} if (process.env.NODE_ENV !== 'production') {
checkStateShape(mappedDispatch, 'mapDispatchToProps')
}
return mappedDispatch
} updateStatePropsIfNeeded() {
const nextStateProps = this.computeStateProps(this.store, this.props)
if (this.stateProps && shallowEqual(nextStateProps, this.stateProps)) {
return false
} this.stateProps = nextStateProps
return true
} updateDispatchPropsIfNeeded() {
const nextDispatchProps = this.computeDispatchProps(this.store, this.props)
if (this.dispatchProps && shallowEqual(nextDispatchProps, this.dispatchProps)) {
return false
} this.dispatchProps = nextDispatchProps
return true
} updateMergedPropsIfNeeded() {
const nextMergedProps = computeMergedProps(this.stateProps, this.dispatchProps, this.props)
if (this.mergedProps && checkMergedEquals && shallowEqual(nextMergedProps, this.mergedProps)) {
return false
} this.mergedProps = nextMergedProps
return true
} isSubscribed() {
return typeof this.unsubscribe === 'function'
} trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(this.handleChange.bind(this))
this.handleChange()
}
} tryUnsubscribe() {
if (this.unsubscribe) {
this.unsubscribe()
this.unsubscribe = null
}
} componentDidMount() {
this.trySubscribe()
} componentWillReceiveProps(nextProps) {
if (!pure || !shallowEqual(nextProps, this.props)) {
this.haveOwnPropsChanged = true
}
} componentWillUnmount() {
this.tryUnsubscribe()
this.clearCache()
} clearCache() {
this.dispatchProps = null
this.stateProps = null
this.mergedProps = null
this.haveOwnPropsChanged = true
this.hasStoreStateChanged = true
this.haveStatePropsBeenPrecalculated = false
this.statePropsPrecalculationError = null
this.renderedElement = null
this.finalMapDispatchToProps = null
this.finalMapStateToProps = null
} handleChange() {
if (!this.unsubscribe) {
return
} const storeState = this.store.getState()
const prevStoreState = this.state.storeState
if (pure && prevStoreState === storeState) {
return
} if (pure && !this.doStatePropsDependOnOwnProps) {
const haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded, this)
if (!haveStatePropsChanged) {
return
}
if (haveStatePropsChanged === errorObject) {
this.statePropsPrecalculationError = errorObject.value
}
this.haveStatePropsBeenPrecalculated = true
} this.hasStoreStateChanged = true
this.setState({ storeState })
} getWrappedInstance() {
invariant(withRef,
`To access the wrapped instance, you need to specify ` +
`{ withRef: true } as the fourth argument of the connect() call.`
) return this.refs.wrappedInstance
} render() {
const {
haveOwnPropsChanged,
hasStoreStateChanged,
haveStatePropsBeenPrecalculated,
statePropsPrecalculationError,
renderedElement
} = this this.haveOwnPropsChanged = false
this.hasStoreStateChanged = false
this.haveStatePropsBeenPrecalculated = false
this.statePropsPrecalculationError = null if (statePropsPrecalculationError) {
throw statePropsPrecalculationError
} let shouldUpdateStateProps = true
let shouldUpdateDispatchProps = true
if (pure && renderedElement) {
shouldUpdateStateProps = hasStoreStateChanged || (
haveOwnPropsChanged && this.doStatePropsDependOnOwnProps
)
shouldUpdateDispatchProps =
haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps
} let haveStatePropsChanged = false
let haveDispatchPropsChanged = false
if (haveStatePropsBeenPrecalculated) {
haveStatePropsChanged = true
} else if (shouldUpdateStateProps) {
haveStatePropsChanged = this.updateStatePropsIfNeeded()
}
if (shouldUpdateDispatchProps) {
haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded()
} let haveMergedPropsChanged = true
if (
haveStatePropsChanged ||
haveDispatchPropsChanged ||
haveOwnPropsChanged
) {
haveMergedPropsChanged = this.updateMergedPropsIfNeeded()
} else {
haveMergedPropsChanged = false
} if (!haveMergedPropsChanged && renderedElement) {
return renderedElement
} if (withRef) {
this.renderedElement = createElement(WrappedComponent, {
...this.mergedProps,
ref: 'wrappedInstance'
})
} else {
this.renderedElement = createElement(WrappedComponent,
this.mergedProps
)
} return this.renderedElement
}
} Connect.displayName = connectDisplayName
Connect.WrappedComponent = WrappedComponent
Connect.contextTypes = {
store: storeShape
}
Connect.propTypes = {
store: storeShape
} if (process.env.NODE_ENV !== 'production') {
Connect.prototype.componentWillUpdate = function componentWillUpdate() {
if (this.version === version) {
return
} // We are hot reloading!
this.version = version
this.trySubscribe()
this.clearCache()
}
} return hoistStatics(Connect, WrappedComponent)
}
}

妈蛋!!!这次有点长,不过不要慌!抓主干!为了更容易理解,我打算从React的生命周期函数的执行顺序讲解!!相信看到我这篇文章的时候,你已经对React有一定的了解,如果还不清楚

React的生命周期函数的执行顺序,看我的正式学习React(三) 和 正式学习React(三)番外篇!或者去官网,或者去谷歌吧。默认我就当大家都知道了!!

1:首先我们要知道connect函数返回的是一个包装类的func,为什么叫它包装类的func,因为它对我们App组件进一步封装,你可以看到的

<Provider store={store}>

<App/>

</Porvider>

其实是:

<Provider store={store}>

<connect>

<App/>

</connect>

</Porvider>

2:connect方法声明如下:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])

作用:连接 React 组件与 Redux store

连接操作不会改变原来的组件类,反而返回一个新的已与 Redux store 连接的组件类。 【就是我第一点说明的,加了个connect组件,将store和app关联了起来,其实是和connect关联了起来!】

参数

[mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了这个参数,你的组件将不会监听 Redux store。如果指定了该回调函数中的第二个参数 ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用。

-----------------------------------------------------------------------------------------------------------------------------

我简单补充一下:为什么组件会监听 Redux store的变化?flux的设计理念就是 dispatch ----》reducer--------》setState。 这个函数是将当前的state映射到props上去.

要想更新视图,使组件渲染成DOM都是最新state和props。必须调用setState,那为什么会调用setState,必然是调用了dispatch,那我们在前面的文章里提过,dispacth的时候,会得到最新 state,并且会

调用subscribe里所有的监听函数。那我们的setState就在这些监听函数里调用!!!

一会你就会看到 componentDidMount()里调用了subcribe(handlechange)  handlechange里最终会调用mapStateToProps,最后 this.setState({ storeState })

-----------------------------------------------------------------------------------------------------------------------------------

[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,而且这个对象会与 Redux store 绑定在一起,其中所定义的方法名将作为属性名,合并到组件的 props 中。如果传递的是一个函数,该函数将接收一个 dispatch 函数,然后由你来决定如何返回一个对象,这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起(提示:你也许会用到 Redux 的辅助函数 bindActionCreators())。如果你省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中。如果指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用。

[mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了这个参数,mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。

[options] (Object) 如果指定这个参数,可以定制 connector 的行为。

[pure = true] (Boolean): 如果为 true,connector 将执行 shouldComponentUpdate 并且浅对比 mergeProps 的结果,避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true。

[withRef = false] (Boolean): 如果为 true,connector 会保存一个对被包装组件实例的引用,该引用通过 getWrappedInstance() 方法获得。默认值为 false

------------------------------------------------------------------------------------------------------------------------

3: wrapWithConnect(WrappedComponent){}【主干来了!!!】

return hoistStatics(Connect, WrappedComponent);

hoistStatics不懂没关系,下一篇文章我会讲解。你现在就当它返回Connect,这个Connect是拥有一些WrappedComponent的props的。

这个函数体里我们关心的就是class connect了。

下面我将以生命周期函数的执行顺序讲解 connect!!!!

1:首先我们先去它的constructor里看一看:

             constructor(props, context) {
super(props, context)
this.version = version //来了!来了! context.store也加到了Connect里啦!!这样就保证了Provider和connect里公用了一个store!
this.store = props.store || context.store
//这个函数的代码直接忽略好了
invariant(this.store,
`Could not find "store" in either the context or ` +
`props of "${connectDisplayName}". ` +
`Either wrap the root component in a <Provider>, ` +
`or explicitly pass "store" as a prop to "${connectDisplayName}".`
) //获取当前state
const storeState = this.store.getState() //注意看 this.state,可想而知,之后会在某个地方调用setState 更新视图。整个React-redux项目,将会在connect这里发起更新视图的发起点,因为这里的才有state,子组件我们都是通过props传下去的
this.state = { storeState }
this.clearCache() //这里初始化一些connect的实例属性。里面的具体属性自己看源码,他们的用途,在接下来的用到的时候再讲
}

看完构造函数,我们就最大的收获就是store成为了connect实例的一个属性!并在这里加了state属性!然后初始化了一些属性。。。。。

2:render(){}  这个函数我会讲两次,一次是我们第一次初始化的时候执行,另外就是在Mounted下,我们先看第一次,具体过程大家自己看注释,一步一步走:

  render() {
//这里我们一开始调用了clearCache 给 connect添加了这些属性,并赋予了初始值。
//这里单独用变量取出来用作下面的操作!
const {
haveOwnPropsChanged, //true
hasStoreStateChanged, //true
haveStatePropsBeenPrecalculated, //false
statePropsPrecalculationError, //null
renderedElement // null
} = this //这里给属性还原
this.haveOwnPropsChanged = false
this.hasStoreStateChanged = false
this.haveStatePropsBeenPrecalculated = false
this.statePropsPrecalculationError = null //第一次会跳过。因为statePropsPrecalculationError == null
if (statePropsPrecalculationError) {
throw statePropsPrecalculationError
} //这里都执行render来更新视图了,也很好理解这2个变量。
//肯定是认为应该更新state和proos了
//也要把props分发给子组件了
let shouldUpdateStateProps = true
let shouldUpdateDispatchProps = true //第一次明显跳过 ,因为renderedElement == null
if (pure && renderedElement) {
shouldUpdateStateProps = hasStoreStateChanged || (
haveOwnPropsChanged && this.doStatePropsDependOnOwnProps
)
shouldUpdateDispatchProps =
haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps
} let haveStatePropsChanged = false
let haveDispatchPropsChanged = false if (haveStatePropsBeenPrecalculated) {
haveStatePropsChanged = true
} else if (shouldUpdateStateProps) { //这里厉害了!因为我们要开始调用我们connect的第一个参数了!
haveStatePropsChanged = this.updateStatePropsIfNeeded()
}
// 第一遍shouldUpdateDispatchProps总是true,haveDispatchPropsChanged总是ture。
if (shouldUpdateDispatchProps) { haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded()
} let haveMergedPropsChanged = true // 第一遍
if (
haveStatePropsChanged ||
haveDispatchPropsChanged ||
haveOwnPropsChanged
) {
haveMergedPropsChanged = this.updateMergedPropsIfNeeded()
} else {
haveMergedPropsChanged = false
} //没变化就返回之前的组件。
if (!haveMergedPropsChanged && renderedElement) {
return renderedElement
} //不然就将mergedProps 当新的props给App
if (withRef) {
this.renderedElement = createElement(WrappedComponent, {
...this.mergedProps,
ref: 'wrappedInstance'
})
} else { this.renderedElement = createElement(WrappedComponent,
this.mergedProps
)
} return this.renderedElement
}

3:componentDidMount(){}

render完成之后就到了这一步。这是生命函数的固定顺序!

里面很简单,就是调用了trySubscribe(){}

trySubscribe这个函数我有必要讲一下:
     trySubscribe() {
// shouldSubscribe 是干嘛的??我们先不管它,假设条件成立!
if (shouldSubscribe && !this.unsubscribe) { //开始订阅函数啦! 这是关键呀,以后我们更新视图全在handleChange里进行
this.unsubscribe = this.store.subscribe(this.handleChange.bind(this)) this.handleChange()
}
} //如果state或者props发生改变,就调用setState。
handleChange() {
if (!this.unsubscribe) {
return
} const storeState = this.store.getState()
const prevStoreState = this.state.storeState if (pure && prevStoreState === storeState) {
return
} if (pure && !this.doStatePropsDependOnOwnProps) {
const haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded, this)
if (!haveStatePropsChanged) {
return
}
if (haveStatePropsChanged === errorObject) {
this.statePropsPrecalculationError = errorObject.value
}
this.haveStatePropsBeenPrecalculated = true
} this.hasStoreStateChanged = true
this.setState({ storeState })
} // shouldSubscribe 为false,直接第一次渲染后不再更新视图了 // const shouldSubscribe = Boolean(mapStateToProps)
// mapStateToProps的重要性也凸显出来了!!!

4:如果上面的setState被调用,就到了

shouldComponentUpdate() {

//不纯的默认更新

// this.haveOwnPropsChanged == true  发生在第一次构造connect 的时候,还有就是props被修改的时候。
//
return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged
} 出场了。。。。。。然后看不是要继续render()

5:componentWillReceiveProps(nextProps){}  当调用了dispath的时候,就会触发setState,然后就可能会触发这个。。。。

6:componentWillUnmount(){}   这个把刚才订阅取消。


总的来说。我们要更加关注render里做的事情,还有trySubscribe里的handle! 第一次流程走通之后,以后每次dispatch,我们就都会执行handle,只有执行了handle才会有后面的生命周期函数执行。

react-redux就是将react和redux结合在一起。 react负责UI, redux负责业务逻辑,

下面给几个图,大家结合着看吧:
最后补充一下 connect 参数的实例:
down voteaccepted
function mapStateToProps(state) {
return {
user: state.app.user
};
} function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(LoginActions, dispatch),
routerActions: bindActionCreators({pushState}, dispatch)
}
} export default connect(mapStateToProps, mapDispatchToProps)(LoginPage);

正式学习React(五) react-redux源码分析的更多相关文章

  1. Redux源码分析之applyMiddleware

    Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...

  2. Redux源码分析之createStore

    接着前面的,我们继续,打开createStore.js, 直接看最后, createStore返回的就是一个带着5个方法的对象. return { dispatch, subscribe, getSt ...

  3. Redux源码分析之基本概念

    Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...

  4. Flask框架(五) —— session源码分析

    Flask框架(五) —— session源码分析 目录 session源码分析 1.请求来了,执行__call__方法 2.__call__方法 3.调用__call__方法 3.1.ctx = s ...

  5. Redux源码分析之bindActionCreators

    Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...

  6. Redux源码分析之combineReducers

    Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...

  7. Redux源码分析之compose

    Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...

  8. React事件杂记及源码分析

    前提 最近通过阅读React官方文档的事件模块,发现了其主要提到了以下三个点  调用方法时需要手动绑定this  React事件是一种合成事件SyntheticEvent,什么是合成事件?  事件属性 ...

  9. Java源码解析——集合框架(五)——HashMap源码分析

    HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...

  10. Redis学习之zskiplist跳跃表源码分析

    跳跃表的定义 跳跃表是一种有序数据结构,它通过在每个结点中维持多个指向其他结点的指针,从而达到快速访问其他结点的目的 跳跃表的结构 关于跳跃表的学习请参考:https://www.jianshu.co ...

随机推荐

  1. PostgreSQL-数据目录与pg&lowbar;ctl

    # tail /etc/profile PATH="$PATH":/usr/lib/postgresql/9.2/bin/ export PATH export PGDATA=/v ...

  2. 基于MPI的并行计算—矩阵向量乘

    以前没接触过MPI编程,对并行计算也没什么了解.朋友的期末课程作业让我帮忙写一写,哎,实现结果很一般啊.最终也没完整完成任务,惭愧惭愧. 问题大概是利用MPI完成矩阵和向量相乘.输入:Am×n,Bn× ...

  3. Git-it:一个学习Git和Github的教程&lpar;软件&rpar;

    Git-it https://github.com/jlord/git-it 2016-08-01 在FreeCodeCamp的引导下了解到的Git-it.OSC有收录. Git-it是一个指导使用G ...

  4. 一个基于angularJS的工资计算器

    先看界面: 其实在ng中最让人印象深刻的就是数据的双向绑定,在html中就完成了很多操作.大概用到的就是控制器视图服务等,没有分模块写控制器,代码如下: <html ng-app = &quot ...

  5. 关于反射和JVM的整理

  6. C&plus;&plus;基础知识--DAY4

    今天主要讲的是类中除了构造器析构器以外的拷贝构造器,运算符重载等问题 首先是拷贝构造器 1. copy constructor(拷贝构造) 其也是构造器,其地位和constructor的地位是一样的 ...

  7. Python 多进程编程之multiprocessing--Process

    Python 多进程编程之multiprocessing 1,Process 跨平台的进程创建模块(multiprocessing), 支持跨平台:windowx/linux 创建和启动      创 ...

  8. 10个Python面试常问的问题

    概述 Python是个非常受欢迎的编程语言,随着近些年机器学习.云计算等技术的发展,Python的职位需求越来越高.下面我收集了10个Python面试官经常问的问题,供大家参考学习. 类继承 有如下的 ...

  9. innodb&lowbar;buffer&lowbar;pool&lowbar;size&equals;30G

    Starting program: /usr/local/mysql-5.6.27-linux-glibc2.5-x86_64/bin/mysqld-debug --user=mysql --data ...

  10. HTML的基本操作学习----常用标签,特殊符号,列表,表格,表单

    什么是HTML 常用标签 标题标签 段落标签 粗体标签+斜体 超链接标签 图片标签 列表标签 无序标签 有序标签 自定义列表 div标签 特殊符号 表格 表单 HTML 什么是 HTML?   HTM ...