赖同学


  • 首页

  • 标签

  • 分类

  • 归档

  • 站点地图

  • 留言

  • 搜索

Redux 的几个核心函数源码

发表于 February 15, 2019|分类于 React|阅读次数: –
字数统计: 1265|阅读时间: 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 — 2023赖彬鸿
1.6k
载入天数...载入时分秒...
0%