react-redux源码解析
react-redux作为大型react应用中链接react和redux的链接库,在很多reat项目中广泛应用。作为开发者的同学们了解reac-redux的原理和源码对我们的能力提升具有一定的帮助,所谓知其然知其所以然。
预备知识
react-redux(建议不知道connectAdvanced API,connectd的四个参数不是特别熟的同学先去简单过一下)
准备工作
老规矩github 找到 react-redux, clone master
本文版本: 6.0.0-beta.3
复制代码
当然你也可以选择看笔者的gitHub项目, 其中包含redux和react-redux的源码及详细的注释
开始撸码
打开项目之后,其他的不多说了,我们直接看src里面的核心代码,从index.js 开始(哦, 这里插一嘴,react-redux是基于react和redux实现的,可以看一下package.json里面的peerDependencies)
一如既往的简单, 暴露出的Provider, connectAdvanced, connect 都有对应的api, 我们先来看看Provider的实现。
Provider实现
我们先想一想reac-redux都干了什么,简单来说用 < Provider >< /Provider>包装了根组件, 把 store 作为 props 传递到每一个被 connect() 包装的组件,其中state to props的计算过程做了优化。 react本身倡导props的自上而下单项传递,但是也提供context支持跨层级传递,到这里,聪明的你是不是联想到了provider与context有关呢,直接看?源码相关注释以添加
建议先看Provider.propTypes提供了那些props -> constructor -> render -> 声明周期钩子方法 -> 总结
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { ReactReduxContext } from './Context'
class Provider extends Component {
constructor(props) {
super(props)
// 获取store
const { store } = props
// 初始化state, storeState为初始的redux state
this.state = {
storeState: store.getState(),
// 保存init store
store
}
}
componentDidMount() {
// 文件收索_isMounted, 共三处, componentWillUnmount中赋值为false
// 先假设为标记componentDidMount -> componentWillUnmount中
this._isMounted = true
// 来看下subscribe
this.subscribe()
}
componentWillUnmount() {
// 取消监听subscribe
if (this.unsubscribe) this.unsubscribe()
// 生命周期结束this._isMounted 赋值为false =>_isMounted假设成立✅
this._isMounted = false
}
componentDidUpdate(prevProps) {
// 如果更新之后,store的引用发生变化
if (this.props.store !== prevProps.store) {
// 如果存在监听则取消
if (this.unsubscribe) this.unsubscribe()
// 更新storeState
this.subscribe()
}
/*
* 在我的理解中redux的store应该是不变的,主要就是为了提供"全局变量state"
* 既然redux作者这样写,我们来思考一下为什么
* 一般store应该是这样 let store = createStore(rootReducer, initState, applyMiddleware(xxx));
* this.props.store !== prevProps.store说明全局的store发生了变化。既createStore方法的重新调用,
* 阅读过redux源码的同学应该知道, 既然是新的createStore, "全局的state"会发生变化,不再是之前的内存空间
* 所有这里再次调用subscribe更新state里面的storeState
*
* * */
}
// 使用store.subscribe方法,保证storeState的最新
subscribe() {
const { store } = this.props
// 监听subscribe
this.unsubscribe = store.subscribe(() => {
// 获取最新的state赋值给newStoreState
const newStoreState = store.getState()
// 不在本次生命周期中return
if (!this._isMounted) {
return
}
this.setState(providerState => {
// If the value is the same, skip the unnecessary state update.
// 如果state是相同的引用, 直接跳过state的更新
if (providerState.storeState === newStoreState) {
return null
}
// 更新当前storeState
return { storeState: newStoreState }
})
})
const postMountStoreState = store.getState()
if (postMountStoreState !== this.state.storeState) {
this.setState({ storeState: postMountStoreState })
}
}
render() {
// ReactReduxContext为默认context, 点过去看一下默认值。 看 -> context.js文件,createContext参数是null
const Context = this.props.context || ReactReduxContext
// value 为this.state
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
Provider.propTypes = {
// 接受store做为props, 并规定store object中的必要方法,既redux createStore的返回对象
store: PropTypes.shape({
subscribe: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
getState: PropTypes.func.isRequired
}),
// 接收自定义context
context: PropTypes.object,
// children, 通常为根容器<app />
children: PropTypes.any
}
export default Provider
/**
* provider总结
*
* provider是react-redux提供是react应用的入口组件, 一般为顶层组件<Provider store={store}><App /></Provider>
* 使用react的context传递store, 老版本的provider用的getChildContext方法, 随着react context的api改变,生产者消费者模式的新api尤然而生,因此
* provider的源码已经重构, 提供的context为{ store, storeState: state},state保存为最新
*
* * */
复制代码
Context.js 提供全局的初始化ReactReduxContext
import React from 'react'
// defaultValue 为 null
export const ReactReduxContext = React.createContext(null)
// export出来,以便提供给provider和consumer使用
export default ReactReduxContext
复制代码
connect 实现
先回顾一下connect的使用形式:
connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])(<Xxx / >)
复制代码
这里还要了解一下connectAdvanced(selectorFactory, [connectOptions])方法,它是一个将 React 组件连接到 Redux store 的函数。这个函数是 connect() 的基础。
由于connect方法内引用文件,function及function的嵌套比较多,如果看官老爷不想过于在意细节,可以直接看一下connect总结
开始看connect源码 -> connect.js,简单看看结构和引用了哪些东西 ->然后我们从export default开始->遇到调用的function再去具体看实现了哪些功能
connect.js
/**
* 先回顾一下connect的参数connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
* 作用:连接 React 组件与 Redux store
* mapDispatchToProps(dispatch, [ownProps])
*
* react-redux 暴露的api, connectAdvanced(selectorFactory, [connectOptions])
* 连接react组件和redux的store, 这个参数是connect的基础
*/
import connectAdvanced from '../components/connectAdvanced'
import shallowEqual from '../utils/shallowEqual'
import defaultMapDispatchToPropsFactories from './mapDispatchToProps'
// mapStateToProps(state, ownProps)
// 只要 Redux store 发生改变,mapStateToProps 函数就会被调用,
// 或者如果有ownProps参数组件接收到新的props,mapStateToProps同样会被调用
import defaultMapStateToPropsFactories from './mapStateToProps'
// mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中
import defaultMergePropsFactories from './mergeProps'
// 定制 connector 如 pure = true 等等等...
import defaultSelectorFactory from './selectorFactory'
/**
*
* 这里先以mapStatetoProps为例子, 其他的同理,简单了解后续用到再看
* @param {*} arg 使用时传进来的mapStatetoProps
* @param {*} factories array[function, function]
* 默认工厂defaultMapStateToPropsFactories, [whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing]
* @param {*} name string
* @returns function
*/
function match(arg, factories, name) {
// 后到前遍历factories
for (let i = factories.length - 1; i >= 0; i--) {
// 调用factories, 返回值赋值给result, 去看 -> mapStateToProps.js
const result = factories[i](arg)
// result为true返回result, result为(dispatch, options) => function(){...}的function
if (result) return result
}
// 不符合connect方法规则throw Error
return (dispatch, options) => {
throw new Error(
`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${
options.wrappedComponentName
}.`
)
}
}
// 判断对象的索引是否相同
function strictEqual(a, b) {
return a === b
}
// 暴露createConnect, 想必肯定会返回function因为connect是个function
export function createConnect({
// 一些带有默认值的参数, 我们看下面, 具体用到了在看?
connectHOC = connectAdvanced, // connectAdvanced(selectorFactory, [connectOptions])
mapStateToPropsFactories = defaultMapStateToPropsFactories, // array[function, function]
mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
mergePropsFactories = defaultMergePropsFactories,
selectorFactory = defaultSelectorFactory
} = {}) {
// 返回的connect function
return function connect(
// connect的四个可选参数
mapStateToProps,
mapDispatchToProps,
mergeProps,
// 配置参数
{
pure = true, // 是否就行浅比较的配置
// 判断是否相同引用的function
areStatesEqual = strictEqual,
// shallowEqual 详情看下面?
areOwnPropsEqual = shallowEqual,
areStatePropsEqual = shallowEqual,
areMergedPropsEqual = shallowEqual,
// 其他配置项
...extraOptions
} = {}
) {
// mapStateToProps初始化
const initMapStateToProps = match(
// 使用时传递的mapStateToProps function
mapStateToProps,
// 默认值 -> 先看match方法, 然后我们来看mapStateToProps.js
mapStateToPropsFactories,
'mapStateToProps'
)
// mapDispatchToProps初始化
const initMapDispatchToProps = match(
mapDispatchToProps,
mapDispatchToPropsFactories,
'mapDispatchToProps'
)
// mergeProps的初始化
const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
// return connectHOC function,将 React 组件连接到 Redux store 的函数
// 先来看看他的参数
// selectorFactory函数返回一个selector函数,根据store state, 展示型组件props,和dispatch计算得到新props,最后注入容器组件
// selectorFactory -> defaultSelectorFactory
// 其实很熟悉react-redux api的同学应该很熟悉connectHOC的参数, 因为他就是connectAdvanced方法啊, 建议先看看api
return connectHOC(selectorFactory, {
// 用于错位信息
methodName: 'connect',
// 用Connect包装getDisplayName
getDisplayName: name => `Connect(${name})`,
// mapStateToProps是否为undefined,shouldHandleStateChanges为false则不监听store state
shouldHandleStateChanges: Boolean(mapStateToProps),
// selectorFactory需要的几个参数
initMapStateToProps, // (dispatch, options) => initProxySelector(dispatch, { displayName }){...}
initMapDispatchToProps,
initMergeProps,
pure, // 默认true
// strictEqual, 这里很容易想到用于判断this.state是不是都一份引用
areStatesEqual,
// shallowEqual浅比较
// 插个题外话,熟悉react PureComponent的同学应该可以快速反应过来!shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState)
// 不熟悉的同学看过来 -> shallowEqual.js
areOwnPropsEqual,
areStatePropsEqual,
areMergedPropsEqual,
// 容错处理, 其他的配置项
...extraOptions
})
}
}
// connect方法 直接调用createConnect
export default createConnect()
复制代码
mapStateToProps.js
import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'
// 当mapStateToProps为function时调用wrapMapToPropsFunc
export function whenMapStateToPropsIsFunction(mapStateToProps) {
return typeof mapStateToProps === 'function'
// 看wrapMapToPropsFunc -> wrapMapToProps.js
? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
: undefined
}
// match中的数组倒着遍历先看这里
// 容错处理, 判断是否传递mapStateToProps参数
export function whenMapStateToPropsIsMissing(mapStateToProps) {
// 如果传递了mapStateToProps参数且!mapStateToProps = true返回undefined,此时result为undefined,无效调用
// 没有传递mapStateToProps参数或mapStateToProps=false -> wrapMapToPropsConstant
return !mapStateToProps ? wrapMapToPropsConstant(() => ({})) : undefined
}
// export default是array,元素为function
export default [whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing]
/**
* 小结:
*
* mapstateToprops参数可执行时调用wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
* 不传递mapstateToprops参数时 wrapMapToPropsConstant(() => ({}))
* 我们接着刨根问底 看->wrapMapToProps.js
*
* * */
复制代码
wrapMapToProps.js
import verifyPlainObject from '../utils/verifyPlainObject'
/**
*
* @export mapstateToprops为undefined调用
* @param {*} getConstant () => ({})
* @returns function initConstantSelector(dispatch, options)
*/
export function wrapMapToPropsConstant(getConstant) {
// 返回 initConstantSelector
return function initConstantSelector(dispatch, options) {
const constant = getConstant(dispatch, options)
function constantSelector() {
return constant
}
constantSelector.dependsOnOwnProps = false
return constantSelector
}
}
// 用来判断是否存在ownProps
// mapStateToProps(state, [ownProps])
export function getDependsOnOwnProps(mapToProps) {
// 不是第一次调用直接返回Boolean
return mapToProps.dependsOnOwnProps !== null &&
mapToProps.dependsOnOwnProps !== undefined
? Boolean(mapToProps.dependsOnOwnProps)
// 第一次调用时mapToProps的dependsOnOwnProps为undefined,直接判断参数个数
: mapToProps.length !== 1
}
/**
* @export mapstateToprops传递时调用
* @param {*} mapToProps 使用connect是传递的mapStateToProprs
* @param {*} methodName 名称 methodName = 'mapStatetoProps' || 'mapDispatchToProps'
* @returns 返回initProxySelector(dispatch, { displayName })
*/
export function wrapMapToPropsFunc(mapToProps, methodName) {
// 终于找到你!! 返回initProxySelector function, 这个返回值会赋值给initMapStateToProps(当然还有initDispatchToProps)
return function initProxySelector(dispatch, { displayName }) {
// 定义proxy function,且作为返回值
const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) {
return proxy.dependsOnOwnProps // mapStateToProps计算是否依赖组件的props
? proxy.mapToProps(stateOrDispatch, ownProps) // 返回proxy.mapToProps,继续看一下他是什么鬼?
: proxy.mapToProps(stateOrDispatch)
}
// dependsOnOwnProps标记运行依赖组件的props为true
proxy.dependsOnOwnProps = true
// detectFactoryAndVerify为返回的function
// 梳理一下,目前调用链是这样的
// const initMapStateToProps = initProxySelector(dispatch, { displayName })=>
// mapToPropsProxy(stateOrDispatch, ownProps) => detectFactoryAndVerify(stateOrDispatch, ownProps)
// detectFactoryAndVerify赋值给proxy.mapToProps
// 第一次调用 mapToPropsProxy时返回detectFactoryAndVerify(stateOrDispatch, ownProps)
proxy.mapToProps = function detectFactoryAndVerify(
stateOrDispatch,
ownProps
) {
// 调用的时候 mapToPropsfunction 赋值给 proxy.mapToProps
// 也就是第一次除了调用到proxy.mapToProps之后, 以后在调用到proxy.mapToProps的时候则使用传递的mapToProps function
proxy.mapToProps = mapToProps
// 重新判断 dependsOnOwnProps(第一次默认true)
proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps)
// 定义props为proxy(stateOrDispatch, ownProps)
// 先看下执行顺序 第一次调用initProxySelector() => proxy() =>
// 此时 proxy.mapToProps = detectFactoryAndVerify()
// 再次调用 proxy(stateOrDispatch, ownProps)时 返回值为传递的mapToProps(...args),也就是我们react组件需要的props
let props = proxy(stateOrDispatch, ownProps)
// 如果props为function再次执行
if (typeof props === 'function') {
proxy.mapToProps = props
proxy.dependsOnOwnProps = getDependsOnOwnProps(props)
props = proxy(stateOrDispatch, ownProps)
}
// 非production环境检查
if (process.env.NODE_ENV !== 'production')
// verifyPlainObject是utils方法, 如果不是纯对象,抛出warning
verifyPlainObject(props, displayName, methodName)
// 返回最终的props
return props
}
return proxy
}
}
复制代码
mergeProps.js和mapDisptchToPtops.js同理,返回一个array[function,function],对参数做容错处理,返回一个initProxySelector function() => proxy => props, 具体细节后面介绍
shallowEqual
shallowEqual通常用来对object做浅比较,经常会出现在react应用中, 配合shouldComponentUpdate做性能优化, 如果熟悉PureComponent原理同学,那应该知道这段代码
!shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState)
复制代码
shallowEqual.js
// 对象自身属性中是否具有指定的属性
const hasOwn = Object.prototype.hasOwnProperty
// 判断两个值是否是相同的值
function is(x, y) {
// SameValue algorithm
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y;
} else {
return x !== x && y !== y;
}
}
// 浅比较 只会比较到两个对象的 ownProperty 是否符合 Object.is 判等,不会递归地去深层比较
// shallowEqual({x:{}},{x:{}}) // false
// shallowEqual({x:1},{x:1}) // true
export default function shallowEqual(objA, objB) {
// 相同值直接返回true,shallowEqual返回值为boolean
if (is(objA, objB)) return true
// 在objA和objB不是相同值的前提下, 如果objA,objB为null或非object可以判定返回false
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false
}
// 定义objA,objB的key数组
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
// length不同说明object不同
if (keysA.length !== keysB.length) return false
// 循环遍历keysA
for (let i = 0; i < keysA.length; i++) {
// 如果objB不含有objA的key且objA与objB的value不同, 返回false
if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
return false
}
}
// 如果通过了for循环, 说明objA, objB中的第一层key和value都相同,恭喜通过
return true
}
复制代码
connect总结
由于connect函数设计的方法过多,我们在这里简化一下connect的代码(以下为源码的精简伪代码)
// 首先为以参数的形式为connect注入一些方法
export function createConnect({
...
// connectAdvanced为react-redux暴露出的api
connectHOC = connectAdvanced,
...
} = {}) {
// connect方法
return function connect(
// 接受的四个参数
mapStateToProps,
mapDispatchToProps,
mergeProps,
{
pure = true, // 是否就行浅比较的配置
strictEqual, // 判断object引用, strictEqual(a, b)=> a === b
shallowEqual, // 浅比较,上面介绍了
...extraOptions // 其他配置项
} = {}
) {
// 一系列的方法执行,对三个参数的类型做了容错处理
// 分别初始化了各自的参数mapStateToProps,mapDispatchToProps,mergeProps,注入了一些内部的默认参数和方法
// 他们大致是这样的function:
// (dispatch, options) => initProxySelector() => mapToPropsProxy() => props
const initMapStateToProps = match(...args)
const initMapDispatchToProps = match(...args)
const initMergeProps = match(...args)
// 返回值由执行connectAdvanced获取,并传入初始化的initMapStateToProps等参数和pure等配置项
return connectAdvanced(selectorFactory, {
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
pure,
...extraOptions
})
}
}
// 直接执行createConnect方法返回connect
export default createConnect()
复制代码
connectAdvanced高阶函数
从connect()(<A/ >)中不难看出connect的返回值为一个高阶组件,包装当前的react组件,返回一个增强props的组件,在执行connect时会执行connectAdvanced,接下来我们不得不看下connectAdvanced方法的实现,先介绍一下connectAdvanced -> ?看注释
connectAdvanced.js
// hoist-non-react-statics组件,这个组件会自动把所有绑定在对象上的非React静态(static)方法都绑定到新的对象上
import hoistStatics from 'hoist-non-react-statics'
// 提示信息插件
import invariant from 'invariant'
import React, { Component, PureComponent } from 'react'
import { isValidElementType } from 'react-is'
// context
import { ReactReduxContext } from './Context'
/**
*
* @export 介绍下connectAdvanced
* connect() 的基础,真正将 React 组件连接到 Redux store 的函数
* @param {*} selectorFactory function selectorFactory(dispatch, factoryOptions)
* 初始化选择器函数,该选择器函数是在 connector 组件需要重新计算一个新的 props 时调用
* 作为 store 的 state 改变或者接收到一个新的 props 的结果。selector 的结果应该是一个普通对象,
* 作为被包裹的组件的 props 传递。如果连续调用 selector 都返回与上一次调用相同的对象(===),
* 则不会重新渲染该组件。selector 的责任是在适当的时候返回以前的对象。
* @param {*} [{
* getDisplayName = name => `ConnectAdvanced(${name})`, DisplayName
* methodName = 'connectAdvanced',
* renderCountProp = undefined,
* shouldHandleStateChanges = true,
* storeKey = 'store',
* withRef = false,
* context = ReactReduxContext,
* ...connectOptions
* }={}]
* @returns
*/
export default function connectAdvanced(
// function, 使用的时候在介绍selectorFactory.js
selectorFactory,
// options object:
{
// 被包裹的组件的 DisplayName 属性
getDisplayName = name => `ConnectAdvanced(${name})`,
// 用于显示错误消息
methodName = 'connectAdvanced',
// 组件是否订阅 redux store 的 state 更改
shouldHandleStateChanges = true,
renderCountProp = undefined, // 传递给内部组件的props键,表示render方法调用次数
// 可以获取 store 的 props/context key
storeKey = 'store',
// 如果为 true,则将一个引用存储到被包裹的组件实例中,并通过 getWrappedInstance() 方法使其可用
withRef = false,
// 看到这个变量我的第一反应是ref的转发, 不了解的同学去看一下React.forwardRef()
forwardRef = false,
// provider的ReactReduxContext方法
context = ReactReduxContext,
...connectOptions
} = {}
) {
// invariant 一个只在development环境的error
// When process.env.NODE_ENV is not production, the message is required.
// 这几个配置参数别使用的时候会有warnning,直接跳过这部分
invariant(
renderCountProp === undefined,
`renderCountProp is removed. render counting is built into the latest React dev tools profiling extension`
)
invariant(
!withRef,
'withRef is removed. To access the wrapped instance, use a ref on the connected component'
)
const customStoreWarningMessage =
'To use a custom Redux store for specific components, create a custom React context with ' +
"React.createContext(), and pass the context object to React-Redux's Provider and specific components" +
' like: <Provider context={MyContext}><ConnectedComponent context={MyContext} /></Provider>. ' +
'You may also pass a {context : MyContext} option to connect'
invariant(
storeKey === 'store',
'storeKey has been removed and does not do anything. ' +
customStoreWarningMessage
)
// 定义Context
const Context = context
// 返回react高阶组件, WrappedComponent既包装的react组件
return function wrapWithConnect(WrappedComponent) {
// 参数检验
if (process.env.NODE_ENV !== 'production') {
invariant(
isValidElementType(WrappedComponent),
`You must pass a component to the function returned by ` +
`${methodName}. Instead received ${JSON.stringify(WrappedComponent)}`
)
}
// 组件的displayName,默认Component
const wrappedComponentName =
WrappedComponent.displayName || WrappedComponent.name || 'Component'
// 拼接下displayName
const displayName = getDisplayName(wrappedComponentName)
// 定义selectorFactoryOptions对象,包含了connect和connectAdvanced的所有参数
const selectorFactoryOptions = {
// connectOptions为initMapStateToProps,initMapDispatchToProps,pure等参数
...connectOptions,
getDisplayName,
methodName,
renderCountProp,
shouldHandleStateChanges,
storeKey,
displayName,
wrappedComponentName,
WrappedComponent
}
// pure决定shouldComponentUpdate是否进行shwoEqual
const { pure } = connectOptions
// Component赋值给OuterBaseComponent, 用react高阶的继承
let OuterBaseComponent = Component
// 定义FinalWrappedComponent
let FinalWrappedComponent = WrappedComponent
if (pure) {
// 为true用PureComponent
OuterBaseComponent = PureComponent
}
// 接下来直接看 class Connect extends OuterBaseComponent
//
function makeDerivedPropsSelector() {
// 定义变量, 用来保存上一次makeDerivedPropsSelector中的值
// 变量语义化我们不难猜出意义
let lastProps
let lastState
let lastDerivedProps
let lastStore
let sourceSelector
return function selectDerivedProps(state, props, store) { // props为父组件的props
// pure为true时,props和state的引用都没有变化, 直接返回lastDerivedProps(第一次肯定不会成立)
// 这里不难理解, 就是要求你用"纯"的state和props
if (pure && lastProps === props && lastState === state) {
return lastDerivedProps
}
if (store !== lastStore) {
// store赋值lastStore, 更新lastStore
// 除第一次调用外一般不会
lastStore = store
// selectorFactory为connect传入的function,默认值来自selsctorFactory.js的export default
sourceSelector = selectorFactory(
store.dispatch,
selectorFactoryOptions // 所有参数集合
)
}
// props赋值给lastProps
lastProps = props
// state赋值给lastState
lastState = state
// 调用sourceSelector参入redux state和props, 得到最新的props
// 不难看出selectorFactory的返回值为一个function, 目前我们可以猜测到
// selsctorFactory.js的export default function 大体结构是这样(dispatch, selectorFactoryOptions)=>(state, props) => newProps
const nextProps = sourceSelector(state, props)
// 新旧props引用相同
if (lastDerivedProps === nextProps) {
// 直接返回
return lastDerivedProps
}
// 新旧props引用不相同, nextProps赋值给lastDerivedProps
lastDerivedProps = nextProps
// 返回lastDerivedProps
return lastDerivedProps
// 最后我们去看selsctorFactory.js到底如何合并的state和props
}
}
function makeChildElementSelector() {
// 定义props, ref, element变量
let lastChildProps, lastForwardRef, lastChildElement
// 返回function
return function selectChildElement(childProps, forwardRef) {
// 判断新旧props, hre, elelment是否相同
if (childProps !== lastChildProps || forwardRef !== lastForwardRef) {
// 如果不同重新赋值
lastChildProps = childProps
lastForwardRef = forwardRef
lastChildElement = (
// return FinalWrappedComponent, 改变props和ref
<FinalWrappedComponent {...childProps} ref={forwardRef} />
)
}
// react组件
return lastChildElement
}
}
class Connect extends OuterBaseComponent {
constructor(props) {
super(props)
invariant(
forwardRef ? !props.wrapperProps[storeKey] : !props[storeKey],
'Passing redux store in props has been removed and does not do anything. ' +
customStoreWarningMessage
)
// 添加selectDerivedProps和selectChildElement方法
// selectDerivedProps为function是makeDerivedPropsSelector的返回值
this.selectDerivedProps = makeDerivedPropsSelector()
// selectChildElement为function
this.selectChildElement = makeChildElementSelector()
// bind this
this.renderWrappedComponent = this.renderWrappedComponent.bind(this)
}
// value为context,既provider中的{storeState: store.getState(),store}
renderWrappedComponent(value) {
invariant(
value,
`Could not find "store" in the context of ` +
`"${displayName}". Either wrap the root component in a <Provider>, ` +
`or pass a custom React context provider to <Provider> and the corresponding ` +
`React context consumer to ${displayName} in connect options.`
)
// 获取redux state和store
const { storeState, store } = value
// 定义wrapperProps为this.props
let wrapperProps = this.props
let forwardedRef
// forwardRef为真时, Connect组件提供了forwardedRef = {ref}
if (forwardRef) {
// wrapperProps为props中的wrapperProps
wrapperProps = this.props.wrapperProps
// forwardedRef赋值为props的forwardedRef, 传递的是ref
// 用于传递给子组件WrappedComponent既let FinalWrappedComponent = WrappedComponent中的FinalWrappedComponent
forwardedRef = this.props.forwardedRef
}
// 导出props
let derivedProps = this.selectDerivedProps(
storeState,
wrapperProps,
store
)
// 返回最终的组件,传入最终的props和ref -> 看selectChildElement发放
return this.selectChildElement(derivedProps, forwardedRef)
}
render() {
// 默认情况下公用的ReactReduxContext
const ContextToUse = this.props.context || Context
return (
// <Privoder />的消费者
<ContextToUse.Consumer>
{this.renderWrappedComponent}
</ContextToUse.Consumer>
)
}
}
// 相当于插件
// 包装的组件赋值给Connect.WrappedComponent
Connect.WrappedComponent = WrappedComponent
// 添加displayName
Connect.displayName = displayName
// forwardRef为true时
if (forwardRef) {
// 使用react.forwardRef为connect生成的组件的父组件提供孙子(传递给connect的组件)组件
const forwarded = React.forwardRef(function forwardConnectRef(
props,
ref
) {
return <Connect wrapperProps={props} forwardedRef={ref} />
})
// 此时connect()(<xx />)的生成组件为forwarded, 从新挂载displayName和WrappedComponent
forwarded.displayName = displayName
forwarded.WrappedComponent = WrappedComponent
return hoistStatics(forwarded, WrappedComponent)
}
// 将子组件的非React的static(静态)属性或方法合并到父组件
// 返回拓展过props属性的Connect组件
return hoistStatics(Connect, WrappedComponent)
}
}
复制代码
connectAdvanced返回一个react高阶组件, 根据pure,forwardRef配置决定是否采用PureComponent和ref的转移, 通过selectDerivedProps放法生成最终的props,传递给最终返回的react组件,最后我们去看selsctorFactory.js到底如何合并的state和props
selectorFactory
selectorFactory函数返回一个selector函数,根据store state, 展示型组件props和dispatch计算得到新props,最后注入容器组件中
selectorFactory.js实现
import verifySubselectors from './verifySubselectors'
export function impureFinalPropsSelectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch
) {
return function impureFinalPropsSelector(state, ownProps) {
// 执行mergePropsProxy,返回修改后的props
return mergeProps(
mapStateToProps(state, ownProps), // mapStateToProps执行结果
mapDispatchToProps(dispatch, ownProps), // mapDispatchToProps的执行结果
ownProps // 自身的props
)
}
}
export function pureFinalPropsSelectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch,
// areStatesEqual判断是否是相同的引用
// areOwnPropsEqual, areStatePropsEqual为shallowEqual
{ areStatesEqual, areOwnPropsEqual, areStatePropsEqual }
) {
// hasRunAtLeastOnce标记第一次执行
// 先看return的function,再看其他的function都做了什么
let hasRunAtLeastOnce = false
let state
let ownProps
let stateProps
let dispatchProps
let mergedProps
// 第一次执行时
function handleFirstCall(firstState, firstOwnProps) {
// 直接赋值以下结果
state = firstState
ownProps = firstOwnProps
stateProps = mapStateToProps(state, ownProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
// hasRunAtLeastOnce标记为true
hasRunAtLeastOnce = true
// 返回mergedProps
return mergedProps
}
function handleNewPropsAndNewState() {
// 获取当前新的的state
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
// 返回mergedProps function内部为新的object
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
// 自身props改变
function handleNewProps() {
// dependsOnOwnProps之前介绍过,判断是否有第一个参数ownprops
// 如果存在需要重新执行,获取新的stateProps和mapDispatchToProps,因为自身的props改变了
if (mapStateToProps.dependsOnOwnProps)
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
// redux state改变
function handleNewState() {
const nextStateProps = mapStateToProps(state, ownProps)
// 浅比较nextStateProps和stateProps
const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)
// 更新stateProps
stateProps = nextStateProps
//statePropsChanged为ture,浅比较失败,mergedProps需要重新计算,mergedProps返回新对象
if (statePropsChanged)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
function handleSubsequentCalls(nextState, nextOwnProps) {
// 执行的时候ownProps浅比较
const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps)
// 比较redux state的引用
const stateChanged = !areStatesEqual(nextState, state)
// nextState赋值给state
state = nextState
// nextOwnProps赋值给onwProps
ownProps = nextOwnProps
// props && state change
// 看不同情况对应的return function
if (propsChanged && stateChanged) return handleNewPropsAndNewState()
// props change
if (propsChanged) return handleNewProps()
// state change
if (stateChanged) return handleNewState()
// propsChanged, stateChanged为true认为props,state没有改变,return mergedProps
return mergedProps
}
return function pureFinalPropsSelector(nextState, nextOwnProps) { // state props
return hasRunAtLeastOnce // 默认值为false
? handleSubsequentCalls(nextState, nextOwnProps)
: handleFirstCall(nextState, nextOwnProps)
}
}
// 找到export default
/**
*
*
* @export
* @param {*} dispatch // store.dispatch
* @param {*} {
* initMapStateToProps // 结构initProxySelector(dispatch, { displayName }) => proxy
* initMapDispatchToProps, // 结构 initMergePropsProxy(dispatch, options) => mergePropsProxy
* initMergeProps,
* ...options 其他配置
* }
* @returns selectorFactory function
*/
// finalPropsSelectorFactory和我们的设想结构一致
export default function finalPropsSelectorFactory(
dispatch,
{ initMapStateToProps, initMapDispatchToProps, initMergeProps, ...options }
) {
// 调用initProxySelector得到proxy function, proxy包含mapToProps, dependsOnOwnProps属性
const mapStateToProps = initMapStateToProps(dispatch, options)
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
// mergePropsProxy为function
// 返回值为connect(mapstate,mapdispatch,function mergeProps(){})()中mergeProps的返回值
const mergeProps = initMergeProps(dispatch, options)
// 非production环境检验 mapStateToProps,mapDispatchToProps,mergeProps
if (process.env.NODE_ENV !== 'production') {
verifySubselectors(
mapStateToProps,
mapDispatchToProps,
mergeProps,
options.displayName
)
}
// pure为true时表示selectorFactory的返回值缓存, 根据当前的redux state和ownProps的变化尽量做最出小的改变
// 详情看pureFinalPropsSelectorFactory
// 否则返回新对象
const selectorFactory = options.pure
? pureFinalPropsSelectorFactory
: impureFinalPropsSelectorFactory
// 执行selectorFactory
// selectorFactory为工厂函数,返回selector
return selectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps, // function mergePropsProxy
dispatch,
options
)
}
复制代码
mergedProps实现
import verifyPlainObject from '../utils/verifyPlainObject'
export function defaultMergeProps(stateProps, dispatchProps, ownProps) {
// 返回一个新对象
return { ...ownProps, ...stateProps, ...dispatchProps }
}
export function wrapMergePropsFunc(mergeProps) {
// initMergeProps
return function initMergePropsProxy(
dispatch,
{ displayName, pure, areMergedPropsEqual }
) {
// 第一次运行,设置为false
let hasRunOnce = false
let mergedProps
return function mergePropsProxy(stateProps, dispatchProps, ownProps) {
// mergeProps的返回结果
const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps)
if (hasRunOnce) {
// pure为fales 或者mergedProps为null
if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps))
mergedProps = nextMergedProps
} else {
// 不是第一次运行,hasRunOnce标记为false
hasRunOnce = true
// nextMergedProps赋值给mergedProps
mergedProps = nextMergedProps
if (process.env.NODE_ENV !== 'production')
verifyPlainObject(mergedProps, displayName, 'mergeProps')
}
// 返回修改后的props
return mergedProps
}
}
}
export function whenMergePropsIsFunction(mergeProps) {
// 如果mergeProps为true且是function, 调用wrapMergePropsFunc返回function initMergePropsProxy(){}
return typeof mergeProps === 'function'
? wrapMergePropsFunc(mergeProps)
: undefined
}
export function whenMergePropsIsOmitted(mergeProps) {
// mergeProps !== true retun () => { ...ownProps, ...stateProps, ...dispatchProps }
return !mergeProps ? () => defaultMergeProps : undefined
}
// 后向前执行
export default [whenMergePropsIsFunction, whenMergePropsIsOmitted]
/**
* [mergeProps(stateProps, dispatchProps, ownProps): props] (Function):
* 如果指定了这个参数,mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。
* 该回调函数返回的对象将作为 props 传递到被包装的组件中
*/
复制代码