2021-01-29 Redux的源码简单实现

231 阅读3分钟

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

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