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;
ES6模块导出
// index.js
import createStore from "./createStore";
import applyMiddleware from "./applyMiddleware";
import combineReducers from "./combineReducers";
export { createStore, applyMiddleware, combineReducers };
createStore(创建容器)
export default function createStore(reducer, enhancer) {
// 如果存在中间件则执行以下
if (enhancer) {
return enhancer(createStore)(reducer);
}
// 初始state为undefined也可以为用户传进来的,暂时没设置
let currentState;
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);
// 返回一个函数删除currentListeners里的监听函数
return () => {
const index = currentListeners.indexOf(listener);
currentListeners.splice(index, 1);
};
}
// 初始化的时候执行下dispatch,设置初始值
dispatch({ type: "REDUXXXXXXXXXXXX" });
return {
getState,
dispatch,
subscribe
};
}
applyMiddleware(组合中间件)
import compose from "./compose";
export default function applyMiddleware(...middlewares) {
return createStore => reducer => {
// 得到store
const store = createStore(reducer);
// 普通版的dispatch
let dispatch = store.dispatch;
// 加强版的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 };
};
}
combineReducers(组合多个reducers为单一reducer)
export default function combineReducers(reducers) {
return function combination(state = {}, action) {
let nextState = {};
let hasChanged = false;
for (const key in reducers) {
const reducer = reducers[key];
nextState[key] = reducer(state[key], action);
hasChanged = hasChanged || nextState[key] !== state[key];
}
// 动态改变reducer
hasChanged =
hasChanged || Object.keys(nextState).length !== Object.keys(state).length;
return hasChanged ? nextState : state;
};
}
redux-thunk中间件
中间件处理场景的dispatch为函数的情况,例如有异步逻辑
// 手写一个thunk,处理异步的thunk
export default function thunk({ getState, dispatch }) {
return next => action => {
// next是聚合函数applyMiddlerware里的compose()
// action相当于dispatch
if (typeof action === "function") {
return action(dispatch, getState);
}
return next(action);
};
}
redux-logger中间件
打印日志
// 手写一个logger,日志打印
export default function logger({ getState, dispatch }) {
return next => action => {
console.log("---------------");
console.log(action.type + "执行了");
const preState = getState();
console.log("pre state", preState);
const returnValue = next(action);
const nextState = getState();
console.log("next state", nextState);
console.log("---------------");
return returnValue;
};
}
最后完整的代码地址github