赖同学


  • 首页

  • 标签

  • 分类

  • 归档

  • 站点地图

  • 留言

  • 搜索

Redux 的几个核心函数源码

发表于 February 15, 2019|分类于 React|阅读次数: –
字数统计: 1267|阅读时间: 7 min

根据订阅发布设计模式看了要模仿的一个功能,看着看着坑越挖越多,涉及到了redux 。顺便尝试吃了一下 redux 的几个核心函数的源码,初生涩隐有启发并作记录。

Redux 的几个核心函数源码

combineReducers

function combineReducers(reducers) {
    const reducerKeys = Object.keys(reducers);
    const finalReducers = {};
    for (let i = 0; i < reducerKeys.length; i++) {
        const key = reducerKeys[i];
        if (process.env.NODE_ENV !== 'production') {
            if (typeof reducers[key] === 'undefined') {
                warning('No reducer provided for key'
                    $ {
                        key
                    });
            }
        }
        if (typeof reducers[key] === 'function') {
            finalReducers[key] = reducers[key]
        }
    }
    const finalReducerKeys = Object.keys(finalReducers);
    let unexpectedKeyCache;
    if (process.env.NODE_ENV !== 'production') {
        unexpectedKeyCache = {};
    }
    let shapeAssertionError;
    try {
        // 判断传入的 reducer 格式是否正确,函数作用为传入的 type 不存在时,是否会返回默认值
        assertReducerShape(finalReducers)
    } catch (e) {
        shapeAssertionError = e;
    }
    return function combination(state = {}, action) {
        // 如果存在不返回默认值的 reducer,抛出异常
        if (shapeAssertionError) {
            throw shapeAssertionError
        }
        // 发出警告 不影响程序执行
        if (process.env.NODE_ENV !== 'production') {
            const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
            if (warningMessage) {
                warning(warningMessage)
            }
        }
        // 记录是否发生了变化,重点
        let hasChanged = false;
        // 要返回的下一个状态
        const nextState = {};
        for (let i = 0; i < finalReducers.length; i++) {
            const key = finalReducerKeys[i];
            const reducer = finalReducers[key];
            // 使用该函数的要求,每个 reducer 的 key 值要和当前操作的 state 的参数同名,比如传入的 card:cardReducer,那么 state 操作的参数就必须是 state.card
            const previousStateForKey = state[key];
            const nextStateForKey = reducer(previousStateForKey, action);
            if (typeof nextStateForKey === 'undefined') {
                const errorMessage = getUndefinedStateErrorMessage(key, action);
                throw new Error(errorMessage);
            }
            // 执行了 reducer 之后的结果
            nextState[key] = nextStateForKey;
            // 每次执行之后的结果,再综合上一次得到的 hasChanged,得到最终的 state 是否发生了变化
            hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
        }
        // 如果发生了变化,就要返回新的 state -> nextState
        return hasChanged ? nextState : state;
    }
}

bindActionCreators

function bindActionCreator(actionCreator, dispatch) {
    return (...args) => dispatch(actionCreator(..args));
}

function bindActionCreators(actionCreators, dispatch) {
    // 可以只传入一个函数作为参数,它会给这个函数的返回结果添加 dispatch 处理
    if (typeof actionCreators === 'function') {
        return bindActionCreator(actionCreators, dispatch);
    }
    if (typeof actionCreators !== 'object' || actionCreators === null) {
        throw new Error(
            `bindActionCreators expected an object or a function,instead received ${actionCreators === null ? 'null' : typeof actionCreators}` +
            `Did you write 'import ActionCreators from' instead of 'immport * as ActionCreators from'?`);
    }
    const keys = Object.keys(actionCreators);
    const boundActionCreators = {};
    for (let i = 0; i < keys.length++; i++) {
        const key = keys[i];
        const actionCreator = actionCreator[key];
        if (typeof actionCreator === 'function') {
            boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
        }
    }
    // 为其添加 dispatch 并返回
    return boundActionCreators;
}

compose

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))
  );
}

applyMiddleware

function applyMiddleware(...middlewares) {
  return createStore => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer);
    let dispatch = store.dispatch;
    // 定义一个存储中间件函数的列表
    let chain = [];
    const middlewareAPI = {
      getState: store.getState,
      dispatch: action => dispatch(action)
    };
    // 这里看出 middleware 需要符合一个规则,接受 getState() 和 dispatch 作为参数
    chain = middlewares.map(middleware => middleware(middlewareAPI));
    dispatch = compose(...chain)(store.dispatch);
    return {
      ...store, // 原来的 store 结构
      dispatch // 增强过的
    };
  };
}

createStore(重点)

图解

function createStore(reducer, preloadedState, enhancer) {
  // 这里操作表明,可以不传第二个参数,不传默认为 undefined
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState;
    preloadedState = undefined;
  }
  if (typeof enhancer !== 'undefined') {
    // enhancer 必须是一个函数
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function');
    }
    // 如果传递 enhancer,则把 createStore 作为参数传递进去,第三个参数不穿也可以,applymiddleware 中会将 createStore 执行并返回
    return enhancer(createStore)(reducer, preloadedState);
  }
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function');
  }

  let currentReducer = reducer;
  // 当前的state
  let currentState = preloadedState;
  // 当前的listeners
  let currentListeners = [];
  let nextListeners = currentListeners;
  // 是否在分发
  let isDispatching = false;

  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice(); // 浅拷贝
    }
  }

  function getState() {
    return currentState;
  }

  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function');
    }
    let isSubscribed = true;
    ensureCanMutateNextListeners();
    nextListeners.push(listener);
    return function unsubscribe() {
      if (!isSubscribed) {
        return;
      }
      isSubscribed = false;
      ensureCanMutateNextListeners();
      const index = nextListeners.indexOf(listener);
      nextListeners.splice(index, 1);
    };
  }

  function dispatch(action) {
    // action 必须是一个对象{type:'xxx'}
    if (!isPlainObject(action)) {
      throw new Error('Actions must be plain object,Use custom middleware for async actions');
    }
    // 对象必须有 type 属性(唯一确定一个 action,不能重复)
    if (typeof action.type === 'undefined') {
      throw new Error('Actions may not have an undefined "type" property.Have you misspelled a constant');
    }
    // 不能同时执行两个 dispatch
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions');
    }
    try {
      isDispatching = true;
      //不论第一次传入currentState是否有值,都会根据第一次的reducer返回默认值
      //比如首次执行createStore就会传入一个几乎不会存在于reducer的case中的类型,这样就可以返回第一次传入reducer的默认值了。
      currentState = currentReducer(currentState, action);
    } finally {
      //放开dispatch入口
      isDispatching = false;
    }
    const listeners = (currentListeners = nextListeners);
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i];
      listener();
    }
    return action;
  }

  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function');
    }
    currentReducer = nextReducer;
    dispatch({
      type: ActionTypes.INIT
    });
  }
  // 一个正规的 reducer 都会返回一个默认值,执行这一步 是为了返回 reducer 的默认值
  dispatch({
    type: ActionTypes.INIT
  });
  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer
  };
}
redux
JavaScript设计模式——单例模式
CSS 中省略号的几种写法
  • 文章目录
  • 站点概览
  1. 1.Redux 的几个核心函数源码
    1. 1.combineReducers
    2. 2.bindActionCreators
    3. 3.compose
    4. 4.applyMiddleware
    5. 5.createStore(重点)
© 2018 — 2025赖彬鸿
载入天数...载入时分秒...
0%