正式学习React(五) react-redux源码分析
磨刀不误砍柴工,咱先把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??!!!------------------------------
现在主角登场:
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
|
|
正式学习React(五) react-redux源码分析的更多相关文章
- Redux源码分析之applyMiddleware
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Redux源码分析之createStore
接着前面的,我们继续,打开createStore.js, 直接看最后, createStore返回的就是一个带着5个方法的对象. return { dispatch, subscribe, getSt ...
- Redux源码分析之基本概念
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Flask框架(五) —— session源码分析
Flask框架(五) —— session源码分析 目录 session源码分析 1.请求来了,执行__call__方法 2.__call__方法 3.调用__call__方法 3.1.ctx = s ...
- Redux源码分析之bindActionCreators
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Redux源码分析之combineReducers
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Redux源码分析之compose
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- React事件杂记及源码分析
前提 最近通过阅读React官方文档的事件模块,发现了其主要提到了以下三个点 调用方法时需要手动绑定this React事件是一种合成事件SyntheticEvent,什么是合成事件? 事件属性 ...
- Java源码解析——集合框架(五)——HashMap源码分析
HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...
- Redis学习之zskiplist跳跃表源码分析
跳跃表的定义 跳跃表是一种有序数据结构,它通过在每个结点中维持多个指向其他结点的指针,从而达到快速访问其他结点的目的 跳跃表的结构 关于跳跃表的学习请参考:https://www.jianshu.co ...
随机推荐
- SolrCloud初识
文章摘自:http://www.bubuko.com/infodetail-923588.html 一.概述 Lucene是一个Java语言编写的利用倒排原理实现的文本检索类库: Solr是以Luce ...
- ubuntu apt 命令参数(转)
apt-get是一条linux命令,适用于deb包管理式的操作系统,主要用于自动从互联网的软件仓库中搜索.安装.升级.卸载软件或操作系统. apt-get update 在修改/etc/apt/sou ...
- KEIL UV3中光标不对齐解决
Keil uVision3与uV2相比增加了对更多型号单片机的支持,另外还对一些的方面进行了优化.不过它却优化出一个让人头疼的问题,那就是光标位置显示不正确!这一问题给程序的编写带来了许多不便.不过不 ...
- 新技术:Qt for Native Client (and emscripten)
http://blog.qt.io/blog/2015/09/25/qt-for-native-client-and-emscripten/
- linux网络配置相关文件
网络接口(interface)是网络硬件设备在操作系统中的表示方法,比如网卡在Linux操作系统中用ethX,是由0开始的正整数,比如eth0.eth1...... ethX.而普通猫和ADSL的接口 ...
- Java里的equals总结
前段时间一直在工作中使用Java,由于有一些C++功底,于是简单看了一下Java相关的语法便开始编写代码,结果在创建一个自定义类,并将自定义类放入ArrayList中,之后查找ArrayList是否有 ...
- Ext中窗体第二次点击报错或者其内控件不显示的问题,弄了2天才解决,记录下
registerPanel.js: registerPanel = new Ext.form.FormPanel({ id:'registerPanel', layout:'form', autoHe ...
- select与epoll分析
关于select与epoll的区别,网上的文章已是一大堆.不过别人的终究是别人的,总得自己去理解才更深刻.于是在阅读了大量的文章后,再装模作样的看下源码,写下了自己的一些理解. 在开始之前,要明白li ...
- Android 自定义UI--电池
首先看一下效果图, 下面看代码: /** * */ package com.example.batterydemo; import android.content.Context; import an ...
- Mysql存储引擎概念特点介绍及不同业务场景选用依据
目录 MySQL引擎概述 1 MySAM引擎介绍 2 什么是InnoDB引擎? 3 生产环境中如何批量更改MySQL引擎 4 有关MySQL引擎常见企业面试题 MySQL引擎概述 Mysql表存储结构 ...