React-Redux
1. React-Redux 提供的一些公共组件及方法
(1) Provider 组件
这里引用简书里的一张图:
Provider 功能主要有如下两点:
1) 在原组件上包裹一层,使原来整个应用成为Provider的子组件
2) 接收Redux的store作为props, 通过context(上下文)对象传递给子孙组件上的connect
核心代码很精简
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
}
首先,对原组件进行了封装: render方法中,渲染了其子级元素,使整个应用成为Provider的子组件。
(a) this.props.children 用于获取当前组件的所有子组件;
(b) Children.only 用于获取仅有的一个子组件,没有或者超过一个匀会报错。所以注意:确保Provider组件的直接子级为单个封闭元素,切勿多个组件平行放置
· 其次,传递store
(a) constructor方法: Provider 初始化时,获取到props中的store对象;
(b) getChildContext 方法:将外部的store对象放入context对象中,使子孙组件上的connect可以直接访问到context对象中的store.
注: context可以使用子孙组件直接获取父级组件中的数据或方法,而无需一层一层通过props向下传递。 context对象相当于一个独立的空间,父组件通过getChildContext()向该空间内写值; 定义了contextTypes 验证的子孙组件可以通过this.context.xxx, 从context对象中读取xxx字段的值。
(2) connect 方法
1) connect 基本作用:
a. 从context 里获取store
b. 在componentWillMount 里通过mapStateToProps, mapDispatchToProps分别获取stateProp,dispatchProps的值
c. 在componentWillMount 里订阅store的变化
d. 将获得的stateProp, dispatchProps, 还有自生的props合成一个props传给下面组件
2) connect 是一个(高阶)函数,接收新状态及新属性方法及一个需要被包裹注入的组件。它会返回一个connect类,里面包着我们要渲染的wrappedComponent , 然后将stateProps,dispatchProps,还有ownProps合并起来,一起传给wrappedComponent(被重注入新props及操作行为的组件)
3) connect可以接受四个参数: mapStatetToProps, mapDispatchToProps, mergeProps, options
4) connect 帮我们做了性能的优化,当state根props发生改变时,selector如果变化,最终计算出来的结果会进行一次浅比较来设置shouldComponentUpdate防止重复渲染。
5) connect 源码:
export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {
class Connect extends Component {
static contextTypes = {
store: PropTypes.object
}
constructor () {
super()
this.state = {
allProps: {}
}
}
componentWillMount () {
const { store } = this.context
this._updateProps()
store.subscribe(() => this._updateProps())
}
_updateProps () {
const { store } = this.context
let stateProps = mapStateToProps
? mapStateToProps(store.getState(), this.props)
: {} // 防止 mapStateToProps 没有传入
let dispatchProps = mapDispatchToProps
? mapDispatchToProps(store.dispatch, this.props)
: {} // 防止 mapDispatchToProps 没有传入
this.setState({
allProps: {
...stateProps,
...dispatchProps,
...this.props
}
})
}
render () {
return <WrappedComponent {...this.state.allProps} />
}
}
return Connect
}
未完待续.....