简单的API
回忆一下创建一个store的方式
import { createStore } from 'redux';
const store = createStore(reducer, [preloadedState], enhancer)
store中包含有以下方法:
- getState() 获取state
- dispatch(action) 更新state
- subscribe() 注册监听器
通过subscribe添加事件监听,dispatch更改state,触发事件,达到我们的目的,这看起来是不是就像是一个订阅发布系统?自信一点,把像去掉
createStore
createStore主要作用,保存state,返回三个方法
const createStore = (reducer) => {
let state;
const getState = () => state;
const subscribe = (listener) => {
//
}
const dispatch = (action) => {
//
}
return {
getState,
subscribe,
dispatch,
}
}
getState 方法最简单,作用就是将state直接返回
subscribe
这里我们需要使用一个listeners数组来存储所有的订阅,subscribe的作用就是将传入的listener加入该数组,注意subscribe是有返回值的,用来取消订阅
const subscribe = (listener) => {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
}
}
dispatch
调用reducer更新state,并触发所有回调函数
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
}
我们还需要在createStore加上一个dispatch({})用作初始化state
combinReducers
在写之前我们看看他的用法吧
import { createStore, combineReducers } from 'redux';
const nameReducer = (prevState, action) => {
switch (action.type) {
case 'CHANGE_NAME':
return action.payload;
default:
return 'jack';
}
};
const ageReducer = (prevState, action) => {
switch (action.type) {
case 'INCREA_AGE':
return prevState + 1;
case 'DECREA_AGE':
return prevState - 1;
default:
return 18;
}
}
const store = createStore(combineReducers({ name: nameReducer, age: ageReducer }));
console.log(store.getState().name) // jack
他接收一个对象,对象的key表示最后在store中储存的值得key,value则是处理这个值得reducer;这个reducer中拿到的prevState为自身的值。
createStore将combineReducers的返回值的作为第一个参数,这里可以看出combineReducers为一个高阶函数,返回值是一个归总的reducer,可以推导出大致结构
const combineReducers = (reducers) => {
return (state = {}, action) => {
///
}
}
内部返回的这个reducer,我们需要将reducers的key进行遍历,然后执行相应的reducer,最后改变state的值返回;
const combineReducers = (reducers) => {
return (state = {}, action) => {
const nextState = {};
Object.keys(reducers).forEach((key) => {
const prevState = state[key];
const currentReducers = reducers[key];
nextState[key] = currentReducers(prevState, action);
});
return nextState;
}
}
完成并使用
那么redux基本的几个api就实现了,搭配上react检验一波,reducer我们使用上面使用过的name和age
const nameReducer = (prevState, action) => {
switch (action.type) {
case 'CHANGE_NAME':
return action.payload;
default:
return 'jack';
}
};
const ageReducer = (prevState, action) => {
switch (action.type) {
case 'INCREA_AGE':
return prevState + 1;
case 'DECREA_AGE':
return prevState - 1;
default:
return 18;
}
}
const rootReducer = combineReducers({ name: nameReducer, age: ageReducer });
const store = createStore(rootReducer);
const Hello = () => {
const state = store.getState();
const dispatch = store.dispatch;
return (
<div>
<p>name: {state.name}----- age: {state.age}</p>
<button onClick={() => dispatch({ type: 'INCREA_AGE' })}>年龄+</button>
<button onClick={() => dispatch({ type: 'DECREA_AGE' })}>年龄-</button>
</div>
)
}
const render = () => {
ReactDom.render(<Hello />, document.getElementById('root'));
}
store.subscribe(render);
render();
完美运行,界面如下
总结
本章对总结了redux基本的几个api,实现思路和源码一致,细节上扔有差异,主要体现在
- 省去了异常处理
- 源码初始化为触发一个私有的action type --
@@redux/INIT
本文直接使用dispatch({})
替代 replaceReducer
因为个人开发使用较少,且实现简单,基本就是当前的reducer
替换为传入的replaceReducer
- redux 新版本已转为ts
redux源码很少,且简单易懂,推荐大家去github阅读源码
文中示例代码目录地址:github.com/Yang-yu-don…