redux手动实现之五终篇

现在已经完成了一个很通用的 createStore ,并且使用起来也很容易,性能也ok。重新审视一下我们代码,发现 stateChanger 第一个参数 state 就是 createStore 第一个参数的 state,两者其实都是全局变量 appState , 那么是否可以将 appState 和 stateChanger 合并到一起? 这样使用 createStore 的时候就可以不用关注 state , 也避免了无意中的 state.title.text="xxx" 这样的代码。

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
function stateChanger(state, action) {
if(!state){
state = {
title: {
text: "redux",
color: "red",
},
content: {
text: "redux文档内容",
color: "blue"
}
};
}
switch (action.type) {
case "UPDATE_TITLE_TEXT": {
state.title.text = action.text;
break;
}
case "UPDATE_TITLE_COLOR": {
state.title.color = action.color;
break;
}
default:
break;
}
}

这时 stateChanger 就同时拥有了初始化和修改 state 的能力,如果有传入 state 就生成更新数据,否则就是初始化数据。

现在可以优化 createStore 为一个参数,将原来的参数 state 变为一个局部遍历,在完成 createStore 的操作之前,通过触发一个空操作,完成局部变量 state 的初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function createStore(stateChanger) {
let state = null;
let events = [];
let store = {
subscribe: (event) => {
events.push(event);
},
dispatch: (action) => {
// 每次修改之后, 获取新的state
state = stateChanger(state, action);
events.forEach((event) => event());
},
getState: () => state
};
// 触发一个空操作, 初始化 state
store.dispatch({});
return store;
}

现在我们就拥有了一个最终形态的 createStore , 它接收一个可以根据 action 修改 state 的函数,这个函数是一个不依赖外部数据,并且没有副作用的纯函数(Pure Function),现在我们把 stateChanger 改为 reducer 就完全符合 redux 的 api 了。

完整代码:

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>

<body>
<div id='title'></div>
<div id='content'></div>

<script>
// const appState = {
// title: {
// text: "redux",
// color: "red",
// },
// content: {
// text: "redux文档内容",
// color: "blue"
// }
// };

function reducer(state, action) {
if (!state) {
state = {
title: {
text: "redux",
color: "red",
},
content: {
text: "redux文档内容",
color: "blue"
}
};
}
switch (action.type) {
case "UPDATE_TITLE_TEXT":
return { // 构建新的对象并且返回
...state,
title: {
...state.title,
text: action.text
}
};
case "UPDATE_TITLE_COLOR":
return { // 构建新的对象并且返回
...state,
title: {
...state.title,
color: action.color
}
};
default:
return state; // 没有修改,返回原来的对象
}
}

// 添加 createStore
function createStore(stateChanger) {
let state = null;
let events = [];
let store = {
subscribe: (event) => {
events.push(event);
},
dispatch: (action) => {
// 每次修改之后, 获取新的state
state = stateChanger(state, action);
events.forEach((event) => event());
},
getState: () => state
};
// 触发一个空操作, 初始化 state
store.dispatch({});
return store;
}

function renderTitle(newTitle, oldTile = {}) {
if (newTitle === oldTile) {
return false;// 数据没有变化就不渲染了
}
console.log("render title...");
const titleDom = document.querySelector("#title");
titleDom.innerHTML = newTitle.text;
titleDom.style.color = newTitle.color;
}

function renderContent(newContent, oldContent = {}) {
if (newContent === oldContent) {
return false;// 数据没有变化就不渲染了
}
console.log("render content...");
const contentDom = document.querySelector("#content");
contentDom.innerHTML = newContent.text;
contentDom.style.color = newContent.color;
}

function renderApp(newAppState, oldAppState = {}) {
if (newAppState === oldAppState) {
return false;// 数据没有变化就不渲染了
}
console.log("render app...");
renderTitle(newAppState.title, oldAppState.title);
renderContent(newAppState.content, oldAppState.content);
}

// 生成 store
let store = createStore(reducer);
// 缓存旧的state
let oldState = store.getState();
// 监听数据变化
store.subscribe(() => {
// 获取新的 state
let newState = store.getState();
// 把新旧的 state 传进去渲染
renderApp(newState, oldState);
// 新的 newState 变成了旧的 oldState,等待下一次数据变化重新渲染
oldState = newState;
});
renderApp(store.getState());
// 三秒钟之后,修改标题和标题颜色,并重新渲染
setTimeout(function () {
store.dispatch({ type: "UPDATE_TITLE_TEXT", text: "Redux是React是好基友" });
store.dispatch({ type: "UPDATE_TITLE_COLOR", color: "green" });
// renderApp(store.getState());
}, 3000);

</script>
</body>

</html>

参考

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