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)地輸出組件需要的(最小)屬性。
(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)頁面交互
shouldComponentUpdate時(shí)判斷是否有避免進(jìn)行渲染既绩,提升頁面性能概龄,并得到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()
}
...