动手实现react-redux之四mapDispatchToProps

重构 ThemeSwitch 组件除了需要 store 里面的数据,还需要通过 store 的 dispatch 来修改数据。现在 connect 还提供不了这个功能,需要进一步改进 connect。

仿照给 connect 传入 mapStateToProps 函数来达到获取指定数据的效果,给 connect 再提供一个 mapDispatchToProps 函数来告诉 connect 组件需要如何调用 dispatch。这个函数应该是这样的:

1
2
3
4
5
6
7
const mapDispatchToProps = (dispatch) => {
return {
onSwitchColor: (color) => {
dispatch({ type: "CHANGE_THEME_COLOR", themeColor: color });
}
};
};

mapDispatchToProps 也是返回一个对象,和 mapStateToProps 不同的地方是传入的参数不是 state ,而是 dispatch。下面来修改 connect ,让他可以处理 mapDispatchToProps。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import React from "react";
import PropTypes from "prop-types";

function connect(mapStateToProps, mapDispatchToProps) {
return (WrappedComponent) => {
class Connect extends React.Component {
static contextTypes = {
store: PropTypes.object
};

state = {
allProps: {}
};

componentWillMount() {
const { store } = this.context;
// 挂载的时候,进行第一次渲染
this.updateProps();
// 然后订阅 store 的后续变化,并更新
store.subscribe(() => this.updateProps());
}

updateProps() {
const { store } = this.context;
const state = store.getState();
// 额外传入 props,让获取数据更加灵活方便
let stateProps = mapStateToProps ? mapStateToProps(state, this.props) : {};
let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : {};
this.setState({
// 整合普通的 props 和从 state 生成的 props
allProps: {
...this.props,
...stateProps,
...dispatchProps
}
});
}

render() {
// let { } = this.props;
return (
<WrappedComponent {...this.state.allProps} />
);
}
}

return Connect;
};
}

export default connect;

这时候我们就可以重构 ThemeSwitch,让它摆脱 store.dispatch 和 context。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import React, { Component } from "react";
import PropTypes from "prop-types";
import connect from "./connect";

class ThemeSwitch extends Component {

static propTypes = {
color: PropTypes.string,
switchColor: PropTypes.func.isRequired
};

// 更新store中的颜色
handleSwitchColor(color) {
this.props.switchColor(color);
}

render() {
return (
<div>
<button
style={{ color: this.props.themeColor }}
onClick={this.handleSwitchColor.bind(this, "red")}
>
设置主题颜色red
</button>
<button
style={{ color: this.props.themeColor }}
onClick={this.handleSwitchColor.bind(this, "green")}
>
设置主题颜色green
</button>
</div>
);
}
}

function mapStateToProps(state, props) {
return {
themeColor: state.themeColor
};
}

function mapDispatchToProps(dispatch, props) {
return {
switchColor: (color) => {
dispatch({ type: "CHANGE_THEME_COLOR", themeColor: color });
}
};
}

export default connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch);

这时候这三个组件的重构都已经完成了,代码大大减少、不依赖 context,并且功能和原来一样。

参考

http://huziketang.mangojuice.top/books/react/