手写Redux源码

10 篇文章 0 订阅
4 篇文章 0 订阅
  • 入口函数 index.js
export { default as createStore } from "./createStore"
export { default as bindActionCreators } from "./bindActionCreators"
export { default as combineReducers } from "./combineReducers"
export { default as applyMiddleware } from "./applyMiddleware"
export { default as compose } from "./compose"
  • utils/ActionTypes.js
/**
 * 得到一个指定长度的随机字符串
 * @param {*} length 
 */
function getRandomString(length) {
  return Math.random().toString(36).substr(2, length).split("").join(".")
}

export default {
  INIT() {
    return `@@redux/INIT${getRandomString(6)}`
  },
  UNKNOWN() {
    return `@@redux/PROBE_UNKNOWN_ACTION${getRandomString(6)}`
  }
}
  • utils/isPlainObject.js
/**
 * 判断某个对象是否是一个plain-object
 * @param {*} obj 
 */
export default function isPlainObject(obj) {
  if (typeof obj !== "object") {
    return false;
  }
  return Object.getPrototypeOf(obj) === Object.prototype;
}
  • createStore.js
import ActionTypes from "./utils/ActionTypes"
import isPlainObject from "./utils/isPlainObject"

/**
 * 实现createStore的功能
 * @param {function} reducer reducer
 * @param {any} defaultState 默认的状态值
 */
export default function createStore(reducer, defaultState, enhanced) {
    //enhanced表示applymiddleware返回的函数
    if (typeof defaultState === "function") {
        //第二个参数是应用中间件的函数返回值
        enhanced = defaultState;
        defaultState = undefined;
    }
    if (typeof enhanced === "function") {
        //进入applyMiddleWare的处理逻辑
        return enhanced(createStore)(reducer, defaultState);
    }

    let currentReducer = reducer, //当前使用的reducer
        currentState = defaultState; //当前仓库中的状态

    const listeners = [];  //记录所有的监听器(订阅者)

    function dispatch(action) {
        //验证action
        if (!isPlainObject(action)) {
            throw new TypeError("action must be a plain object");
        }
        //验证action的type属性是否存在
        if (action.type === undefined) {
            throw new TypeError("action must has a property of type");
        }
        currentState = currentReducer(currentState, action)
        //运行所有的订阅者(监听器)
        for (const listener of listeners) {
            listener();
        }
    }

    function getState() {
        return currentState;
    }

    /**
     * 添加一个监听器(订阅器)
     */
    function subscribe(listener) {
        listeners.push(listener); //将监听器加入到数组中
        let isRemove = false;//是否已经移除掉了
        return function () {
            if (isRemove) {
                return;
            }
            //将listener从数组中移除
            const index = listeners.indexOf(listener);
            listeners.splice(index, 1);
            isRemove = true;
        }
    }

    //创建仓库时,需要分发一次初始的action
    dispatch({
        type: ActionTypes.INIT()
    })

    return {
        dispatch,
        getState,
        subscribe
    }
}
  • combineReducers.js
import isPlainObject from "./utils/isPlainObject"
import ActionTypes from "./utils/ActionTypes"

function validateReducers(reducers) {
  if (typeof reducers !== "object") {
    throw new TypeError("reducers must be an object");
  }
  if (!isPlainObject(reducers)) {
    throw new TypeError("reducers must be a plain object");
  }
  //验证reducer的返回结果是不是undefined
  for (const key in reducers) {
    if (reducers.hasOwnProperty(key)) {
      const reducer = reducers[key];//拿到reducer
      //传递一个特殊的type值
      let state = reducer(undefined, {
        type: ActionTypes.INIT()
      })
      if (state === undefined) {
        throw new TypeError("reducers must not return undefined");
      }
      state = reducer(undefined, {
        type: ActionTypes.UNKNOWN()
      })
      if (state === undefined) {
        throw new TypeError("reducers must not return undefined");
      }
    }
  }
}

export default function (reducers) {
  //1. 验证
  validateReducers(reducers);
  /**
   * 返回的是一个reducer函数
   */
  return function (state = {}, action) {
    const newState = {}; //要返回的新的状态
    for (const key in reducers) {
      if (reducers.hasOwnProperty(key)) {
        const reducer = reducers[key];
        newState[key] = reducer(state[key], action);
      }
    }
    return newState; //返回状态
  }
}
  • bindActionCreators.js
export default function (actionCreators, dispatch) {
  if (typeof actionCreators === "function") {
    return getAutoDispatchActionCreator(actionCreators, dispatch);
  }
  else if (typeof actionCreators === "object") {
    const result = {}; //返回结果
    for (const key in actionCreators) {
      if (actionCreators.hasOwnProperty(key)) {
        const actionCreator = actionCreators[key]; //取出对应的属性值
        if (typeof actionCreator === "function") {
          result[key] = getAutoDispatchActionCreator(actionCreator, dispatch);
        }
      }
    }
    return result;
  }
  else {
    throw new TypeError("actionCreators must be an object or function which means action creator")
  }
}

/**
 * 得到一个自动分发的action创建函数
 */
function getAutoDispatchActionCreator(actionCreator, dispatch) {
  return function (...args) {
    const action = actionCreator(...args)
    dispatch(action);
  }
}
  • compose.js
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return args => args; //如果没有要组合的函数,则返回的函数原封不动的返回参数
  }
  else if (funcs.length === 1) {
    //要组合的函数只有一个
    return funcs[0];
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))

  // return function (...args) {
  //     let lastReturn = null; //记录上一个函数返回的值,它将作为下一个函数的参数
  //     for (let i = funcs.length - 1; i >= 0; i--) {
  //         const func = funcs[i];
  //         if (i === funcs.length - 1) {//数组最后一项
  //             lastReturn = func(...args)
  //         }
  //         else {
  //             lastReturn = func(lastReturn)
  //         }
  //     }
  //     return lastReturn;
  // }
}
  • applyMiddleware.js
import compose from "./compose"
/**
 * 注册中间件
 * @param  {...any} middlewares 所有的中间件
 */
export default function (...middlewares) {
  return function (createStore) { //给我创建仓库的函数
    //下面的函数用于创建仓库
    return function (reducer, defaultState) {
      //创建仓库
      const store = createStore(reducer, defaultState);
      let dispatch = () => { throw new Error("目前还不能使用dispatch") };
      const simpleStore = {
        getState: store.getState,
        dispatch: store.dispatch
      }
      //给dispatch赋值
      //根据中间件数组,得到一个dispatch创建函数的数组
      const dispatchProducers = middlewares.map(mid => mid(simpleStore));
      dispatch = compose(...dispatchProducers)(store.dispatch);
      return {
        ...store,
        dispatch
      }
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值