动手实现react-redux之二组合context和store

在 src/index.js 中添加模拟 redux 时创建的 createStore 函数,并创建一个 themeReducer 用来初始化 state 并维护 state 的更新,通过 themeReducer 生成一个 store。然后将 store 放到 Index 组件的 context 里面,这个每个子组件都可以获取到 store 了。

修改 src/index.js:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import React, { Component } from "react";
import PropTypes from "prop-types";
import ReactDOM from "react-dom";
import Header from "./Header";
import Content from "./Content";
import "./index.css";

function createStore(reducer) {
let events = [];
let state = null;

let store = {
subscribe: (event) => events.push(event),
dispatch: (action) => {
state = reducer(state, action);
events.forEach((event) => event());
},
getState: () => state
};
// 初始化state
store.dispatch({});
return store;
}

function themeReducer(state, action) {
if (!state) {
return {
themeColor: "red"
};
}
switch (action.type) {
case "CHANGE_THEME_COLOR":
return { ...state, themeColor: action.themeColor };
default:
return state;
}
}

const store = createStore(themeReducer);

class Index extends Component {

static childContextTypes = {
store: PropTypes.object
};

getChildContext() {
return {
store
};
}

render() {
return (
<div>
<Header />
<Content />
</div>
);
}
}

ReactDOM.render(
<Index />,
document.getElementById("root")
);

然后修改 src/Header.js 和 src/Context.js,让它从 Index 的 context 里面获取 store,并且获取里面的 themeColor 状态来设置自己的颜色。

src/Header.js

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
import React, { Component } from "react";
import PropTypes from "prop-types";

class Header extends Component {

static contextTypes = {
store: PropTypes.object
};

state = {
themeColor: ""
};

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

updateThemeColor() {
let state = this.context.store.getState();
this.setState({
themeColor: state.themeColor
});
}

// static getDerivedStateFromProps(nextProps, prevState) {
//
// }


render() {
return (
<h1 style={{ color: this.state.themeColor }}>React-Redux是什么</h1>
);
}
}

export default Header;

src/Context.js

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
import React, { Component } from "react";
import PropTypes from "prop-types";
import ThemeSwitch from "./ThemeSwitch";

class Content extends Component {

static contextTypes = {
store: PropTypes.object
};

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

updateThemeColor() {
let state = this.context.store.getState();
this.setState({
themeColor: state.themeColor
});
}

render() {
return (
<div style={{ color: this.state.themeColor }}>
<p>React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据</p>
<ThemeSwitch />
</div>
);
}
}

export default Content;

修改 src/ThemeSwitch.js,添加颜色更新及两个按钮的点击事件

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
52
53
54
55
56
57
import React, { Component } from "react";
import PropTypes from "prop-types";

class ThemeSwitch extends Component {

static contextTypes = {
store: PropTypes.object
};

state = {
themeColor: ""
};

componentWillMount() {
let { store } = this.context;
this.updateThemeColor();
store.subscribe(() => {
this.updateThemeColor();
});
}

updateThemeColor() {
const { store } = this.context;
const state = store.getState();
this.setState({ themeColor: state.themeColor });
}

// 更新store中的颜色
handleSwitchColor(color) {
let { store } = this.context;
store.dispatch({
type: "CHANGE_THEME_COLOR",
themeColor: color
});
}

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

export default ThemeSwitch;

到此 store 和 context 已经结合起来,看起来功能完成的不错,就是代码稍微啰嗦,后面继续优化。

参考

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