微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

react-redux之Provider源码解析

react-redux简介

redux一个数据管理框架,而react-redux是专门针对react开发的一个插件。react-redux提供了2个API,Providerconnect。本来打算在一篇文章同时讲解2个API的实现,不过看了一下connect的源码,368行,还是分开解析吧。

本文带领大家分析Provider的核心代码

如何使用Provider

我们先了解在react项目中是如何使用Provider。

import { Provider } from 'react-redux';
import configureStore from './store/configureStore';

const store = configureStore();
ReactDOM.render((
    <Provider store={store}>
        
    </Provider>),document.getElementById('root')
);

上面的代码可以看出,使用Provider分为下面几个步骤:

1、导入Provider
这里跟小白分享一个小知识,你可以看到Provider加了个大括号,而第二个import configureStore没有加大括号,这是因为react-redux文件中没有指定default输出。如果指定了export default,则不需要加大括号,注意一个js文件只能有一个default。

import { Provider } from 'react-redux';

2、将store作为参数传入Provider。

<Provider store={store}>
    
</Provider>

Provider源码

import { Component,Children } from 'react'
import PropTypes from 'prop-types'
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 {
  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: storeShape.isrequired,children: PropTypes.element.isrequired
}
Provider.childContextTypes = {
  store: storeShape.isrequired
}

Provider源码解析

Provider只有一个参数,非常简单,代码也仅有55行。

1、Provider是一个react组件

import { Component,Children } from 'react'
import PropTypes from 'prop-types'
import storeShape from '../utils/storeShape'
import warning from '../utils/warning'

export default class Provider extends Component {
  getChildContext() {
    return { store: this.store }
  }

  constructor(props,context)
    this.store = props.store
  }

  render() {
    return Children.only(this.props.children)
  }
}

Provider组件写了3个方法getChildContext、constructor、render

constructor是构造方法,this.store = props.store中的this表示当前的组件。在构造函数定义this.store的作用是为了能够在getChildContext方法中读取到store。

你最不熟悉的可能就是getChildContext,翻译过来就是上下文。什么意思呢?又有什么用呢?我们看到getChildContext方法是返回store。接着,就看不到store哪去了。

后执行render渲染,返回一个react子元素。Children.only是react提供的方法,this.props.children表示的是只有一个root的元素。

2、给Provider组件设置propTypes验证。storeShape是一个封装的方法

Provider.propTypes = {
    store: storeShape.isrequired,children: PropTypes.element.isrequired
}
//storeShape
import PropTypes from 'prop-types'

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

3、验证childContextTypes
它的作用就是让Provider下面的子组件能够访问到store。
详细解释和用法react关于context的介绍

Provider.childContextTypes = {
  store: storeShape.isrequired
}

4、node运行环境判断
如果不是生产环境,也就是在开发环境中,实现componentwillReceiveProps()。

if (process.env.NODE_ENV !== 'production') {
  Provider.prototype.componentwillReceiveProps = function (nextProps) {
    const { store } = this
    const { store: nextStore } = nextProps

    if (store !== nextStore) {
      warnAboutReceivingStore()
    }
  }
}

其实也可以把这段代码写到Provider组件内部去。

他的作用是当接收到新的props的时候,如果是在开发环境下,就判断当前的store和下一个store是不是不相等,如果是,就执行warnAboutReceivingStore()。

export default class Provider extends Component {
  
  componentwillReceiveProps(nextProps) {
    if (process.env.NODE_ENV !== 'production') {
      const { store } = this
      const { store: nextStore } = nextProps

      if (store !== nextStore) {
        warnAboutReceivingStore()
      }
    }
  }
  
  render() {
    return Children.only(this.props.children)
  }
}

5、warnAboutReceivingStore的作用。
上面说到执行了warnAboutReceivingStore,那么warnAboutReceivingStore的作用是什么呢?

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.'
  )

didWarnAboutReceivingStore是一个开关的作用,认是false,也就是不执行warning操作。当props更新的时候,执行了warnAboutReceivingStore(),如果didWarnAboutReceivingStore为true,则return,否则就将didWarnAboutReceivingStore设置为true。然后就会执行warning的警告机制。

这样做的目的是不允许在componentwillReceiveProps做store的更新操作。

总结

很快就到尾声了,Provider是一个react组件,提供了一个参数store,然后渲染了一个子组件,我们通常把路由渲染成子组件,最后还处理了一个异常情况,提供了warning提示

大部分时候是这样用的。在react-router4中,也支持这种写法,Provider也可以直接嵌套在自定义的react组件中。

<Provider store={store}>
      <Router history={hashHistory}>
            {routes}
      </Router>
</Provider>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐