手动实现简易版redux
源码地址:kredux分支
先来回顾下redux工作方式
- store 状态管理容器,内置getState, dispatch, subscribe方法
- state 改变的唯一方式是通过 store.dispatch(action) 来触发reducer,reducer根据action传来的type实现不同的更新state措施
- 由于redux无法异步,所以需要对redux进行扩展,当然不仅针对异步,也可以根据个人需求对dispatch过程进行“订制”。
基于此,要手写一个redux, 首先要实现下面方法
- action
- reducer
- createStore(reducer, enhaner) { reutrn (getState, dispatch, subscribe)}
要对redux进行扩展,需要使用中间件,要完成下面方法:
- applyMiddleware 对原store的dispatch方法进行扩展
- compose 如果接收的扩展方法有多个,则对扩展数组内容逐个扩展 如[a,b],最终实现 a(b(dispatch))
- 扩展方法,如logger/thunk 对dispatch进行拦截,并返回新的dispatch或action
接下来,正文开始
action 页面调用
// src/page/ReduxPage.js
export default class reduxPage extends Component {
componentDidMount(){
store.subscribe(()=>{
this.forceUpdate()
})
}
// action 方法实现
add = () => {
store.dispatch({type: "ADD"})
};
return (
<div>
...
</div>
)
}
reducer 方法
// src/store/index.js
// reducer 实现
function countReducers(state=0, action){
switch(action.type):
case "ADD":
return state + 1;
case "MINU":
return state - 1;
default:
return state
}
// store 创建
const store = createStore(countReducer, applyMiddleware(thunk, logger));
实现 createStore
function createStore(reducer, enhaner){
// 有扩展就执行扩展
if (enhancer) {
return enhancer(createStore)(reducer);
}
let currentState = undefined;
let currentListeners = [];
function getState() {
return currentState;
}
function dispatch(action) {
currentState = reducer(currentState, action);
// 监听函数是一个数组,那就循环吧
currentListeners.map(listener => listener());
}
//订阅,可以多次订阅
function subscribe(listener) {
// 每次订阅,把回调放入回调数组
currentListeners.push(listener);
}
// 取值的时候,注意一定要保证不和项目中的会重复
dispatch({type: "@INIT/REDUX-KKB"});
return {
getState,
dispatch,
subscribe
};
}
进行扩展
applyMiddleware 中间件
// src/kRedux.js
// applyMiddleware(thunk, logger)
export function applyMiddleware(...middlewares) {
return createStore => (...args) => {
// 第一部分 要对原store扩展,先取到原store API
const store = createStore(...args);
let dispatch = store.dispatch;
const middleApi = {
getState: store.getState,
dispatch
};
// 给middleware参数,比如说dispatch, map方法得到的是个全新数组
const middlewaresChain = middlewares.map(middleware =>
middleware(middleApi)
);
dispatch = compose(...middlewaresChain)(dispatch);
return {
...store,
// 覆盖上面store里的dispatch
dispatch
};
};
}
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
// 多个扩展时,依次调用[thunk, logger]
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
扩展方法
// src/store/index.js
// 日志扩展
function logger({getState, dispatch}) {
return dispatch => action => {
console.log(action.type + "执行了");
return dispatch(action);
};
}
// 异步扩展
function thunk({getState, dispatch}) {
return dispatch => action => {
// action 可以是对象 还可以是函数 ,那不同的形式,操作也不同
if (typeof action === "function") {
return action(dispatch, getState);
} else {
return dispatch(action);
}
};
}