2021-01-29 Redux的源码简单实现
Reducer
reducer是什么,其实就是一个纯函数,接收旧的state和action,返回新的state
(preState,action)=>newState
之所以叫reducer,是和Array.prototype.reduce(reducer, initialValue)
里的回调函数属于相同的类型。
保持reducer的纯净非常重要,永远不要再reducer里做以下操作:
- 修改传入参数
- 执行有副作用的操作,如API请求和路由跳转
- 调用非纯函数,如Date.now()或Math.random等
compose
如果一个值要经过多个函数,才能变成另外一个值,就可以把所有中间步骤合并成一个函数,这叫函数的合成(compose)
合成的好处显而易见,它让代码变得更简单而且富有可读性,同时通过不同的组合方式,可以轻易组合出其他常用函数,让代码变得更具有表现力
/**
* 组合函数
*/
function f1(arg) {
console.log("f1", arg);
return arg;
}
function f2(arg) {
console.log("f2", arg);
return arg;
}
function f3(arg) {
console.log("f3", arg);
return arg;
}
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
compose(f1,f2)("omg");
// console.log(compose(f1, f2, f3)("omg"));
Redux
Redux是Javascript应用的状态容器,是纯JS写的,保证程序行为一致性且易于测试
redux应用举例:
1、需要一个store来存储数据
2、store里的reducer初始化state并定义state修改规则
3、通过dispatch一个action来提交对数据的修改
4、action提交到reducer函数里,根据传入的action的type,返回新的state
检查点:
1、createStore创建store
2、reducer初始化、修改状态函数
3、getState获取状态值
4、dispatch提交更新
5、subscribe变更订阅
手写redux相关API
应用容器store index.js
// import { createStore, applyMiddleware, combineReducers } from "redux";
import { createStore, applyMiddleware, combineReducers } from "./kredux";
// import thunk from "redux-thunk"; // 处理异步
// import logger from "redux-logger"; // 打印日志
function countReducer(state = 0, { type, payload }) {
switch (type) {
case "ADD":
return state + payload;
case "MINUS":
return state - payload;
default:
return state;
}
}
const store = createStore(
// countReducer,
combineReducers({ count: countReducer }), // 多个reducer处理
applyMiddleware(thunk, logger)
);
export default store;
导出 kredux/index.js
import createStore from "./createStore";
import applyMiddleware from "./applyMiddleware";
import combineReducers from "./combineReducers";
export { createStore, applyMiddleware, combineReducers };
createStore-API:创建store
export default function createStore(reducer, enhancer) {
// 如果存在中间件则执行以下
if(enhancer){
return enhancer(createStore)(reducer);
}
let currentState; // 初始为null 默认值没有作用(state为undefined走default,内部采用严格相等模式)
let currentListeners = [];
// get
function getState() {
return currentState;
}
// set
function dispatch(action) {
currentState = reducer(currentState, action);
// state改变,执行订阅的函数
currentListeners.forEach(listener => listener());
}
// 订阅和取消订阅要成对出现
function subscribe(listener) {
currentListeners.push(listener);
return () => {
const index = currentListeners.indexOf(listener);
currentListeners.splice(index, 1);
};
}
// 初始化的时候执行下dispatch,设置初始值
dispatch({ type: "REDUXXXXXXX" });
return {
getState,
dispatch,
subscribe
};
}
applyMiddleware-组合中间件
export default function applyMiddleware(...middlewares) {
return createStore => reducer => {
const store = createStore(reducer); // 得到store
// 普通版的dispatch
let dispatch = store.dispatch;
// todo 加强版的dispatch
let midAPI = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args) // 每个中间件都有自己的作用域
};
// 执行中间件数组
const middlewareChain = middlewares.map(middleware => middleware(midAPI));
// 用compose组合函数按顺序执行,得到加强版的dispatch
dispatch = compose(...middlewareChain)(store.dispatch);
return { ...store, dispatch };
};
}
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
combineReducers-组合多个reducers为单一reducer
export default function combineReducers(reducers) {
return function combination(state = {}, action) {
let nextState = {};
let hasChanged = false; // 初始值
for (let key in reducers) {
const reducer = reducers[key];
nextState[key] = reducer(state[key], action);
hasChanged = hasChanged || nextState[key] !== state[key];
}
/**
* 动态改变reducer
* {a: 1, b:2}
* {a: 1 }
*/
hasChanged =
hasChanged || Object.keys(nextState).length !== Object.keys(state).length;
return hasChanged ? nextState : state;
};
}