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

磨刀不误砍柴工,咱先把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);
上一篇:通过 NPOI 生成 Excel


下一篇:Server Tomcat v8.0 Server at localhost failed to start.的解决方法