抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

为了深入理解 Redux 状态管理工具,手写一个简化的(也是作业)

手写一个类似 Redux 的 createStore,实现一个简单的列表增删。

输入名称,序号自增并以此名称添加进列表;输入要删除的序号,就删除对应序号的行

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>redux</title>
</head>
<body>
<div class="add">
<input type="text" placeholder="输入名称" />
<button>添加</button>
</div>
<div class="delete">
<input type="text" placeholder="输入要删除的id" />
<button>删除</button>
</div>
<div class="show"></div>
<script src="./main.js"></script>
</body>
</html>

main.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
67
68
69
70
71
72
73
const addTextDOM = document.querySelector('.add input');
const addBtnDOM = document.querySelector('.add button');
const deleteTextDOM = document.querySelector('.delete input');
const deleteBtnDOM = document.querySelector('.delete button');
const showDOM = document.querySelector('.show');

// 手写简单Redux
function createStore(reducer) {
// 闭包内数据,一个是所存数据,一个是注册的函数
// 初始化 state
let state = reducer(undefined, {});
const listeners = [];

// 从闭包里获取state的函数
const getState = () => state;
// 核心,dispatch函数,使用传入的reducer更新state,同时触发所有注册的函数
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach((listener) => listener());
};
// 注册函数,返回一个取消注册的函数
const subscribe = (listener) => {
listeners.push(listener);

return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
};

return { getState, dispatch, subscribe };
}

// 此例子的reducer,这里state进行了初始化,这样规定了state的数据结构
// names数组里面放的是有id和name俩属性的对象
function reducer(state = { id: 0, names: [] }, action) {
switch (action.type) {
case 'ADD':
return {
id: state.id + 1,
names: [...state.names, { id: state.id, name: action.name }],
};
case 'DELETE':
return {
// 这里重写了展开属性,覆盖了原来的names
...state,
names: state.names.filter((item) => item.id !== action.id),
};
default:
return state;
}
}

// 利用手写的createStore函数创建store
const store = createStore(reducer);
// 渲染函数
function render() {
const currentState = store.getState(); // 获取当前的状态
showDOM.innerHTML = currentState.names.map((item) => `<p>序号:${item.id},名称:${item.name}</p>`).join('');
}
// 注册渲染的函数,同时返回一个取消注册的函数(虽然说没用到吧
const unRender = store.subscribe(render);

addBtnDOM.addEventListener('click', () => {
const name = addTextDOM.value;
store.dispatch({ type: 'ADD', name });
addTextDOM.value = '';
});
deleteBtnDOM.addEventListener('click', () => {
const id = Number(deleteTextDOM.value);
store.dispatch({ type: 'DELETE', id });
deleteTextDOM.value = '';
});

评论