# redux实现
# store
- store提供数据的get钩子(store.getState),不直接提供数据的set,所以必须通过dispatch(action)来set数据。
- 利用观察者模式(sub/ pub)连接model和view的中间对象。view层通过调用store.dispatch方法触发reducer改变model。对应pub。model层通过调用store.subscribe注册视图更新事件(setstate),该事件会在数据改变之后被调用。对应sub。
# reducer
真正改变数据的方法。接受一个旧的state,返回一个新的state。这种改变方式也体现了redux不可变数据的思想。即一个数据产生,就不会变化,如果要改变这个数据,需要返回一个新的数据引用。
# 看一个redux例子
import { createStore } from 'redux';
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);
// 可以手动订阅更新,也可以事件绑定到视图层。
store.subscribe(() =>
console.log(store.getState())
);
// 改变内部 state 惟一方法是 dispatch 一个 action。
// action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1
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
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
可以看到 createStore 函数 获取一个reducer 返回一个对象,该对象有 getState,dispatch,subscribe
# redux实现
function createStore(reducer) {
let state;
let listeners = [];
const getState = () => state;
const subscribe = (ln) => {
listeners.push(ln);
//订阅之后,也要允许取消订阅。不能只准订,不准退~
const unsubscribe = () => {
listeners = listeners.filter(listener => ln !== listener);
}
return unsubscribe;
};
const dispatch = (action) => {
//reducer(state, action) 返回一个新状态
state = reducer(state, action);
listeners.forEach(ln => ln());
}
//你要是有个 action 的 type 的值正好和 `@@redux/__INIT__${Math.random()}` 相等,我敬你是个狠人
dispatch({ type: `@@redux/__INIT__${Math.random()}` });
return {
getState,
dispatch,
subscribe
}
}
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
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
从代码中我们可以看出
getState:返回存储的state数据
subscribe:将要观察的函数放入观察队列中
dispatch:执行reducer获取最新的state,存下来,然后遍历观察队列中的函数
一个简单版的redux完成了