博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React-redux原理探索
阅读量:6924 次
发布时间:2019-06-27

本文共 7519 字,大约阅读时间需要 25 分钟。

先看一段react-redux代码再探索原理

import React from 'react';import { render } from 'react-dom';import { createStore } from 'redux';import { Provider } from 'react-redux';import routes from './router';import reducer from './reducer';const store = createStore(  reducer);render(  
{routes}
, document.getElementById('root'));

先调用redux的createStore生成store,再将store作为属性传给Provider组件。

现在看看react-redux源代码。

index.js页暴露了以下几个接口

export { Provider, createProvider, connectAdvanced, connect }

上面的demo使用的是Provider组件,Provider的主要作用是使得其所有子组件可以通过context访问到Redux的store,现在深入了解一下Provider组件的实现原理。

class Provider extends Component {    // 将store放入context使子孙组件能够访问到store    getChildContext() {      return { [storeKey]: this[storeKey], [subscriptionKey]: null }    }    constructor(props, context) {      super(props, context)      // 获取redux实例      this[storeKey] = props.store;    }    render() {      // 使整个应用成为Provider的子组件      // 确保Provider组件的直接子级为单个封闭元素,切勿多个组件平行放置。      return Children.only(this.props.children)    }  }  // Redux 2.x 与React-Redux 2.x不再支持热重载的reducer,所以在非生产环境下,  // 我们会为Provider添加生命周期函数componentWillReceiveProps,如果store的值发生了变化,就会在提供警告提示  if (process.env.NODE_ENV !== 'production') {    Provider.prototype.componentWillReceiveProps = function (nextProps) {      if (this[storeKey] !== nextProps.store) {        warnAboutReceivingStore()      }    }  }  Provider.propTypes = {    store: storeShape.isRequired,    children: PropTypes.element.isRequired,  }  Provider.childContextTypes = {    [storeKey]: storeShape.isRequired,    [subscriptionKey]: subscriptionShape,  }  return Provider}

connect的作用就是将state和dispatch绑定到react组件中,使得组件可以访问到redux,下面为connect使用demo

export default connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {})(ReactComponent)

connect源代码比较长,把connect的核心实现简化提取出来是下面的形式,最终返回的是把state和dispatch绑定到Connect的组件。

funtion connect(mapStateToProps,mapDispatchToProps,mergeProps,{一堆props}) {
return function wrapWithConnect(WrappedComponent) {        class Connect extends Component {                }        return hoistStatics(Connect, WrappedComponent)    }}

其中hoistStatics(Connect, WrappedComponent)是自动把所有绑定在WrappedComponent对象上的非React方法都绑定到Connect上。

先看看传入的四个参数mapStateToProps,mapDispatchToProps,mergeProps,{一堆props}作用

const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')    const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')    const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')    return connectHOC(selectorFactory, {      // used in error messages      methodName: 'connect',       // used to compute Connect's displayName from the wrapped component's displayName.      getDisplayName: name => `Connect(${name})`,      // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes      shouldHandleStateChanges: Boolean(mapStateToProps),      // passed through to selectorFactory      initMapStateToProps,      initMapDispatchToProps,      initMergeProps,      pure,      areStatesEqual,      areOwnPropsEqual,      areStatePropsEqual,      areMergedPropsEqual,      // any extra options args can override defaults of connect or connectAdvanced      ...extraOptions    })

通过match方法生成新的函数传递给connectHOC(生成Connect组件的方法)

initMapStateToProps分两种情况,不传或者传参为null时返回一个函数(运行传参state返回空对象),传参为函数时返回一个函数(执行后返回state中所传入的属性,例如下边的函数会返回{todo:[]})
const mapStateToProps = state => ({  todos: []})
initMapDispatchToProps分为三种:
  • 不传参时返回函数(函数运行参数传入dispatch,返回对象{dispatch:function dispatch(){xxx}});
  • 传参为函数时返回函数(函数运行传参dispatch返回对象,例如下边函数会返回{
    onClick:function(){xxx}})
const mapDispatchToProps = (dispatch, ownProps) => ({  onClick: () => dispatch(setVisibilityFilter(ownProps.filter))})
  • 传参为对象时返回函数(函数运行传参dispatch,返回{xxx:function(){xxx}})

initMergeProps不传参默认返回 { ...ownProps, ...stateProps, ...dispatchProps }将所有props全部合成一个对象

 

这三种参数全部初始化完毕后执行connectHOC生成Connect组件,Connect组件会初始化两样东西

  • initSelector:selector的主要作用是通过执行initMapStateToProps,initMapDispatchToProps,initMergeProps生成的函数计算新的props,并返回纯对象(plain object),将这个对象作为props传递给被包裹的组件(WrappedComponent)
initSelector() {        // 首先调用selectorFactory从而初始化sourceSelector,我们并不会直接调用sourceSelector,而是为了程序的健壮,        // 通过将sourceSelector作为参数调用makeSelectorStateful,返回更加安全的selector。        // 从此之后,我们想要生成新的props只需要调用selector.run函数。        // 在selector.run函数中对sourceSelector的异常做了处理,并用sourceSelector.error记录是否存在异常        // function pureFinalPropsSelector(nextState, nextOwnProps) {
// return hasRunAtLeastOnce // ? handleSubsequentCalls(nextState, nextOwnProps) // : handleFirstCall(nextState, nextOwnProps) // } const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions) this.selector = makeSelectorStateful(sourceSelector, this.store) this.selector.run(this.props) }

通过执行selector.run设置selector.shouldComponentUpdate再通过shouldComponentUpdate判断selector.shouldComponentUpdate通知组件是否刷新

const selector = {    run: function runComponentSelector(props) {      try {        const nextProps = sourceSelector(store.getState(), props)        if (nextProps !== selector.props || selector.error) {          selector.shouldComponentUpdate = true          selector.props = nextProps          selector.error = null        }      } catch (error) {        selector.shouldComponentUpdate = true        selector.error = error      }    }  }  shouldComponentUpdate() {    return this.selector.shouldComponentUpdate  }
  • initSubscription为store增加监听事件,在store数据变化时执行onStateChange函数
initSubscription() {        if (!shouldHandleStateChanges) return        // parentSub's source should match where store came from: props vs. context. A component        // connected to the store via props shouldn't use subscription from context, or vice versa.        const parentSub = (this.propsMode ? this.props : this.context)[subscriptionKey]        this.subscription = new Subscription(this.store, parentSub, this.onStateChange.bind(this))        this.notifyNestedSubs = this.subscription.notifyNestedSubs.bind(this.subscription)      }

onStateChange函数是store发生改变的回调函数,当回调onStateChange方法时,会通过selector计算新的props,如果计算selcetor的结果中shouldComponentUpdatefalse,表示不需要刷新当前组件仅需要通知子组件更新。如果shouldComponentUpdatetrue,会通过设置this.setState({})来刷新组件,并使得在组件更新结束之后,通知子组件更新。

onStateChange() {        this.selector.run(this.props)        if (!this.selector.shouldComponentUpdate) {          this.notifyNestedSubs()        } else {          this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdate          this.setState(dummyState)        }      }

在render操作时将selector生成的新props作为参数传到WrappedComponent组件中,WrappedComponent组件就是connect()(ReactComponent)中传入的ReactComponent

addExtraProps(props) {        if (!withRef && !renderCountProp && !(this.propsMode && this.subscription)) return props        const withExtras = { ...props }        if (withRef) withExtras.ref = this.setWrappedInstance        if (renderCountProp) withExtras[renderCountProp] = this.renderCount++        if (this.propsMode && this.subscription) withExtras[subscriptionKey] = this.subscription        return withExtras      }      render() {        const selector = this.selector        selector.shouldComponentUpdate = false        if (selector.error) {          throw selector.error        } else {          return createElement(WrappedComponent, this.addExtraProps(selector.props))        }      }

将selector.props中的属性传到WrappedComponent,这个props是经过计算的所有props的合集。

 

参考:

转载于:https://www.cnblogs.com/xcsun/p/9146342.html

你可能感兴趣的文章
Java反射在JVM的实现
查看>>
七牛云存储 迁移资源用代码示例 [Java]
查看>>
MMVM模式
查看>>
java验证身份证号码及编码规则和提取相应信息
查看>>
python的一些使用技巧
查看>>
Windows下Nginx+PHP5的安装与配置方法
查看>>
php-----utf8和gbk相互转换
查看>>
CentOS 7 erlang.mk:30: Please upgrade to GNU Make 4
查看>>
基于centos6.7离线安装docker1.7.1
查看>>
apt安装方式 Mongo
查看>>
mount error(13): Permission denied window
查看>>
ubuntu访问window7的共享文件
查看>>
个人的编程命名习惯的几点记录
查看>>
Android中各种JAVA包的功能描述
查看>>
PHP 从数据库读取写入txt文件
查看>>
Python中有关赋值的奇怪现象
查看>>
jquery radio
查看>>
行为验证的几种方式 google & 网易
查看>>
系统中图片上传设计方案
查看>>
MySQL添加、删除字段、调整字段
查看>>