# 状态管理器
# 简单的状态管理器
redux是一个状态管理器,那什么是状态呢?状态就是数据
,比如计数器中的count。
const state = {
count: 1
};
我们来使用下状态
console.log(state.count);
我们来修改下状态
state.count = 2;
好了,现在我们实现了状态(计数)的修改和使用了。
读者:你当我傻吗?你说的这个谁不知道?
笔者:哎哎哎,别打我!redux核心就是这个呀!我们一步步扩展开来嘛!
当然上面有一个很明显的问题:修改count之后,使用count的地方不能收到通知。
我们可以使用发布-订阅模式
来解决这个问题。
// count 的发布订阅者实践
const state = {
count: 1
};
const listeners = [];
// 订阅
function subscribe(listener) {
listeners.push(listener);
}
function changeCount(count) {
state.count = count;
// 当 count 改变的时候,我们要去通知所有的订阅者
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener();
}
}
我们来尝试使用下这个简单的计数状态管理器。
// 来订阅一下,当 count 改变的时候,我要实时输出新的值
subscribe(() => {
console.log(state.count);
});
// 我们来修改下 state,当然我们不能直接去改 state 了,我们要通过 changeCount 来修改
changeCount(2);
changeCount(3);
changeCount(4);
现在我们可以看到,我们在修改count的时候,会输出相应的count值。
现在有两个新的问题摆在我们面前
- 这个状态管理器只能管理count,不通用
- 公共的代码要封装起来
我们尝试来解决这个问题,把公共的代码封装起来
const createStore = function (initState) {
const state = initState;
const listeners = [];
// 订阅
function subscribe(listener) {
listeners.push(listener);
}
function changeState(newState) {
state = newState;
// 通知
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener();
}
}
function getState() {
return state;
}
return {
subscribe,
changeState,
getState
}
}
我们来使用这个状态管理器管理多个状态counter和info试试
const initState = {
counter: {
count: 0
},
info: {
name: '',
description: ''
}
};
const store = createStore(initState);
store.subscribe(() => {
const state = store.getState();
console.log(`${state.info.name}: ${state.info.description}`);
};
store.subscribe(() => {
const state = store.getState();
console.log(state.counter.count);
});
store.changeState({
...store.getState(),
info: {
name: '前端九部',
description: '我们都是前端爱好者!'
}
});
store.changeState({
...store.getState(),
counter: {
count: 1
}
});
到这里我们完成了一个简单的状态管理器。
这里需要理解的是createStore
,提供了changeState
,getState
,subscribe
三个能力。
本小节完整源码见demo-1 (opens new window)
# 有计划的状态管理器
我们用上面的状态管理器来实现一个自增,自减的计数器。
const initState = {
count: 0
};
const store = createStore(initState);
store.subscribe(() => {
const state = store.getState();
console.log(state.count);
});
// 自增
store.changeState({
count: store.getState().count + 1
});
// 自减
store.changeState({
count: store.getState().count - 1
});
// 不符合规则的随便修改
store.changeState({
count: 'abc'
});
你一定发现了问题,count被改成了字符串abc
,因为我们对count的修改没有任何约束,任何地方、任何人都可以修改。
我们需要约束,不允许计划外的count修改,我们只允许count自增和自减两种改变方式!
那我们分两步来解决这个问题
制定一个state修改计划,告诉store,我的修改计划是什么。
修改store.changeState方法,告诉它修改state的时候,按照我们的计划修改。
我们来设置一个plan函数,接受现在的state和一个action,返回经过改变后的新的state。
// 注意: action = {type: '', other: ''}, action 必须有一个 type 属性
function plan(state, action) {
switch (action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + 1
}
case 'DECREMENT':
return {
...state,
count: state.count - 1
}
default:
return state;
}
}
我们把这个计划告诉store,store.changeState以后改变state要按照我的计划来改。
// 增加一个参数 plan
const createStore = function (plan, initState) {
const state = initState;
const listeners = [];
function subscribe(listener) {
listeners.push(listener);
}
function changeState(action) {
// 请按照我的计划修改 state
state = plan(state, action);
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener();
}
}
function getState() {
return state;
}
return {
subscribe,
changeState,
getState
}
}
我们尝试使用下新的createStore来实现自增和自减
const initState = {
count: 0
};
// 传入 plan 函数
const store = createStore(plan, initState);
store.subscribe(() => {
const state = store.getState();
console.log(state.count);
});
// 自增
store.changeState({
type: 'INCREMENT'
});
// 自减
store.changeState({
type: 'DECREMENT'
});
// 我想随便修改,但是计划外的修改是无效的
store.changeState({
count: 'abc'
});
到这里为止,我们已经实现了一个有计划的状态管理器。
我们商量一下吧?我们把plan和changeState改一下名字好不好?
plan改成reducer,changeState改成dispatch!
不管你同不同意,我都要换,因为新名字比较厉害(其实因为redux是这么叫的)!
本小节完整源码见demo-2 (opens new window)