react-redux的学习实现第三课:由connect完成事件触发,拒绝组件直接调用store内部方法
上一节的学习中,我们在themeSwitch中去切换组件的颜色时,仍然是通过Index上的context去获取store,然后调用store.dispatch去触发事件,回顾代码如下:
handleSwitchColor = (color) => {
const { store } = this.context;
store.dispatch({
type: 'CHANGE_COLOR',
themeColor: color
});
};
本节的学习,就是要跟着react小书去修改themeSwitch组件派发action的方式。 回忆上一节我们给connect传入的mapStateToProps,这个函数的主要目的就是在确定的某一个组件中,确定的向store中的state索取该组件需要的状态值,官方一点的说法就是如何整合/获取状态。那么同样的我们可以再给connect传入一个mapDispatchToProps,来告诉我们的组件如何触发dispatch。 对比之前的mapStateToProps,我们的mapDispatchToProps的代码大致如下:
const mapDispatchToProps = (dispatch) => {
return {
onSwitchColor: (color) => {
dispatch({ type: 'CHANGE_COLOR', themeColor: color })
}
};
};
将上述代码添加进connect的代码,并做调整。
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => (
class 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;
console.log('this.props', this.props);
let stateProps = mapStateToProps ? mapStateToProps(store.getState(), this.props) : {};
let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : {};
this.setState({
allProps: { // 整合普通的 props 和从 state 生成的 props
...stateProps,
...this.props,
...dispatchProps,
}
}, () => {
console.log('this.state.allProps', this.state.allProps);
});
}
render() {
return <WrappedComponent {...this.state.allProps}/>
}
}
);
这是,我们就可以开始正式去修改ThemeSwitch的内容了。
import React, { Component } from 'react';
import PropTypes from "prop-types";
import { connect } from './react-redux';
class ThemeSwitch extends Component {
constructor(props) {
super(props);
this.state = {
themeColor: ''
};
}
// static contextTypes = {
// store: PropTypes.object
// };
static propTypes = {
handleSwitchColor: PropTypes.func,
themeColor: PropTypes.string
};
// componentWillMount() {
// const { store } = this.context;
// this._updateThemeColor();
// store.subscribe(this._updateThemeColor);
// }
//
// _updateThemeColor = () => {
// const { store } = this.context;
// const state = store.getState();
//
// this.setState({
// themeColor: state.themeColor
// });
// };
// handleSwitchColor = (color) => {
// const { store } = this.context;
// store.dispatch({
// type: 'CHANGE_COLOR',
// themeColor: color
// });
// };
render() {
return (
<div>
<button
// style=
style=
// onClick={() => this.handleSwitchColor('red')}
onClick={() => this.props.handleSwitchColor('red')}
>red</button>
<button
// style=
style=
// onClick={() => this.handleSwitchColor('blue')}
onClick={() => this.props.handleSwitchColor('blue')}
>blue</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
themeColor: state.themeColor
}
};
const mapDispatchToProps = (dispatch) => {
return {
handleSwitchColor: (color) => {
dispatch({ type: 'CHANGE_COLOR', themeColor: color })
}
}
};
ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch);
export default ThemeSwitch;
其中有一些被注释的地方,明显对比起来,组件内部的代码少了很多,我们将控制状态和控制函数操作的部分,传给connect,让connect将组件和他们连接起来,这样我们就有了一个干净的纯函数组件,我们只关心传入的内容,而不用在组件内容去调用store中的方法,这样大大提高了组件的复用性。
本节总结:
- 要时刻关注mapStateToProps和mapDispatchToProps的取值问题,它们并不是时时刻刻都需要的,所以要做合适的回退判断,如果不存在,我们就返回一个空对象,这一点尤为重要
- 每一次都要注意修改静态的propTypes,contextTypes,childContextTypes的修改,这上面很容易报错