1、connect
connect用于連接React組件與 Redux store,其使用方法如下
connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])
[mapStateToProps(state, [ownProps]): stateProps]是connect的第一個(gè)參數(shù),其類型為function,允許我們將 store 中的數(shù)據(jù)作為 props 綁定到組件上。
const mapStateToProps = (store) => {
return {
count:store.count
}
}
(1)這個(gè)函數(shù)的第一個(gè)參數(shù)就是 Redux 的 store,我們不必將 store中的數(shù)據(jù)原封不動(dòng)地傳入組件,可以根據(jù) state 中的數(shù)據(jù),動(dòng)態(tài)地輸出組件需要的(最?。傩浴?/p>
(2)函數(shù)的第二個(gè)參數(shù) ownProps,是組件自己的 props。有的時(shí)候,ownProps 也會(huì)對(duì)其產(chǎn)生影響。
當(dāng) state 變化,或者 ownProps 變化的時(shí)候,mapStateToProps 都會(huì)被調(diào)用,計(jì)算出一個(gè)新的 stateProps,(在與 ownProps merge 后)更新給組件。
[mapDispatchToProps(dispatch, ownProps): dispatchProps]將 action 作為 props 綁定到組件上,也會(huì)成為 MyComp 的 props。
stateProps 和 dispatchProps,都需要和 ownProps merge 之后才會(huì)被賦給組件。connect 的第三個(gè)參數(shù)就是用來做這件事。如果不傳這個(gè)參數(shù),connect 就會(huì)使用 Object.assign替代該方法。
connect 的第四個(gè)參數(shù)[options] (Object) 如果指定這個(gè)參數(shù),可以定制 connector 的行為,一般不用。
connect核心代碼:
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
// 從祖先Component處獲得store
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 對(duì)stateProps、dispatchProps、parentProps進(jìn)行合并
this.updateState()
}
shouldComponentUpdate(nextProps, nextState) {
// 進(jìn)行判斷,當(dāng)數(shù)據(jù)發(fā)生改變時(shí),Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
}
}
componentDidMount() {
// 改變Component的state
this.store.subscribe(() = {
this.setState({
storeState: this.store.getState()
})
})
}
render() {
// 生成包裹組件Connect
return (
<WrappedComponent {...this.nextState} />
)
}
}
Connect.contextTypes = {
store: storeShape
}
return Connect;
}
}
可以看到connect是一個(gè)高階函數(shù)
首先,傳入mapStateToProps、mapDispatchToProps
然后,返回一個(gè)生產(chǎn)Component的函數(shù)(wrapWithConnect)
最后,將真正的Component作為參數(shù)傳入wrapWithConnect
這樣就生產(chǎn)出一個(gè)經(jīng)過包裹的Connect組件,該組件具有如下特點(diǎn):
通過props.store獲取祖先Component的storeprops包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作為props傳給真正的Component
componentDidMount時(shí),添加事件this.store.subscribe(this.handleChange),實(shí)現(xiàn)頁(yè)面交互
shouldComponentUpdate時(shí)判斷是否有避免進(jìn)行渲染,提升頁(yè)面性能,并得到nextState
componentWillUnmount時(shí)移除注冊(cè)的事件this.handleChange
2、Provider
Provider組件主要有以下兩個(gè)作用:
1、在原應(yīng)用組件上包裹一層,使原來整個(gè)應(yīng)用成為Provider的子組件
2、接收Redux的store作為props,通過context對(duì)象傳遞給子孫組件
其代碼如下
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是通過context傳遞給子組件的,子組件通過connect獲得數(shù)據(jù),實(shí)現(xiàn)過程如下,可以看到在沒有定義props的情況下,通過context直接取得store中的數(shù)據(jù)。
...
constructor(props, context) {
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
this.updateState()
}
...