實現mini版react redux 1. 理解react redux模塊 1). react redux模塊整體是一個對象模塊 2). 包含2個重要屬性: Provider和connect 3). Provider 值: 組件類 作用: 向所有容器子組件提供全局store對象 使用: 4). co ...
實現mini版react-redux
1. 理解react-redux模塊
1). react-redux模塊整體是一個對象模塊
2). 包含2個重要屬性: Provider和connect
3). Provider
值: 組件類
作用: 向所有容器子組件提供全局store對象
使用: <Provider store={store}><Xxx/></Provider>
4). connect
值: 高階函數
作用: 包裝組件生成容器組件, 讓被包裝組件能與redux進行通信
使用: connect(mapStateToProps, mapDispatchToProps)(Xxx)
2. context的理解和使用
1). 理解
當你覺得多層傳遞props麻煩, 可以選擇使用context
context是組件對象的一個屬性, 它的值是一個對象
一個組件指定的context內數據, 所有層次子組件都可以讀取到
如果可以儘量不用context, 你可以選擇使用react-redux, react-redux內部就利用了context
2). 使用
父組件:
static childContextTypes = {
color: PropTypes.string
}
getChildContext() {
return {color: 'red'};
}
後代組件:
static contextTypes = {
color: PropTypes.string
}
render () {
this.context.color
}
3. 實現代碼: src/libs/react-redux/index.js
import React, {Component} from 'react'
import PropTypes from 'prop-types'
/*
1. Provider組件類
*/
export class Provider extends Component {
// 聲明當前組件接收store
static propTypes = {
store: PropTypes.object.isRequired
}
// 必須聲明向子節點指定全局數據store
static childContextTypes = {
store: PropTypes.object.isRequired
}
// 指定向子組件指定全局數據store
getChildContext() {
return {store: this.props.store};
}
render() {
// 返回所有子節點(如果沒有子節點返回undefined, 如果只有一個子節點它是對象, 如果有多個它是數組)
return this.props.children
}
}
/*
2. connect方法
*/
export function connect(mapStateToProps = () => null, mapDispatchToProps = {}) {
// 返回函數(接收被包裝組件類作為參數)
return (WrapComponent) => {
// 返回一個新的組件類
return class ConnectComponent extends Component {
// 聲明接收全局store
static contextTypes = {
store: PropTypes.object.isRequired
}
// 構造函數的第2個參數為context對象
constructor(props, context) {
super(props)
console.log('constructor', this.context) // 此時組件對象中還沒有context
// 從context中取出store
const {store} = context
// 一般屬性: 調用mapStateToProps函數得到包含所有需要傳遞一般屬性的集合對象
const stateProps = mapStateToProps(store.getState())
// 分發action的函數屬性: 調用自定義的整合函數生成包含多個分發action的函數的對象
const dispatchProps = this.bindActionCreators(mapDispatchToProps)
// 初始化狀態, 包含所有需要傳遞給WrapComponent組件的一般屬性
this.state = {
...stateProps
}
// 將包含dispatch函數的對象保存在組件對象上(不用放到state中)
this.dispatchProps = dispatchProps
}
/*
根據包含多個action creator的對象, 返回一個包含多個分發action的函數的對象
*/
bindActionCreators = (mapDispatchToProps) => {
// 準備一個保存分發action函數的對象容器
const dispatchProps = {}
// 遍歷每個action creator
Object.keys(mapDispatchToProps).forEach((key) => {
// 得到某個action creator
const actionCreator = mapDispatchToProps[key]
//定義包含分發action代碼的函數, 並只在到準備好的容器中
dispatchProps[key] = (...args) => {
this.context.store.dispatch(actionCreator(...args))
}
})
// 返回dispatch代碼函數容器對象
return dispatchProps
}
componentDidMount() {
console.log('componentDidMount', this.constructor)
// 得到store
const {store} = this.context
// 訂閱監聽
store.subscribe(() => {
// 一旦store中的state有變化, 更新組件狀態, 從而導致被包裝組件重新渲染
this.setState(mapStateToProps(store.getState()))
})
}
render() {
return <WrapComponent {...this.state} {...this.dispatchProps} />
}
}
}
}