Redux 源码学习

71 阅读1分钟

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

Redux 有三大原则:应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中(单一数据源);惟一改变 state 的办法是触发 action( state 是只读的);为了描述 action 如何改变 state 树,需要编写 reducer(使用纯函数来执行修改 state)。

redux 的核心是 createStore 函数,来看下他的简单实现:

function createStore(reducer) {
    let listenerIdCounter = 0;
    let currentState = undefined;
    let currentListeners = new Map();
    let nextListeners = currentListeners
    let isDispatching = false;

    function getState() {
        return currentState;
    }

    function subscribe(listener) {
        const listenerId = listenerIdCounter++;

        ensureCanMutateNextListeners();
        nextListeners.set(listenerId, listener);

        return unsubscribe.bind(this, listenerId);
    }

    function unsubscribe(listenerId) {
        ensureCanMutateNextListeners();
        nextListeners.delete(listenerId);
    }

    function disposable(listener) {
        const listenerId = listenerIdCounter++;

        function _disposable(...args) {
            listener.apply(this, args);
            unsubscribe(listenerId);
        }

        ensureCanMutateNextListeners();
        nextListeners.set(listenerId, _disposable);
    }

    function dispatch(action) {
        if (isDispatching) {
            throw new Error('Reducers may not dispatch actions.');
        }

        try {
            isDispatching = true;
            currentState = reducer(currentState, action);
        } finally {
            isDispatching = false;
        }

        const listeners = currentListeners = nextListeners;
            listeners.forEach((listener) => {
                listener();
            });

        return action;
    }

    function ensureCanMutateNextListeners() {
        if (nextListeners === currentListeners) {
            nextListeners = new Map()
            currentListeners.forEach((listener, key) => {
                nextListeners.set(key, listener)
            })
        }
    }

    dispatch({ type: 'INIT' });

    return {
        getState,
        subscribe,
        dispatch,
        disposable,
    };
}

在平时开发中我们还会用到 combineReducers 将多个模块的 state 管理到一棵树上,下面我们看下 combineReducers 到底干了什么:

function combineReducers(reducers) {
    const reducerKeys = Object.keys(reducers);
    const finalReducers = {};
    for (let i = 0; i < reducerKeys.length; i++) {
        const key = reducerKeys[i];

        if (typeof reducers[key] === 'function') {
            finalReducers[key] = reducers[key];
        }
    }
    const finalReducerKeys = Object.keys(finalReducers);

    return function combination(state = {}, action) {
        let hasChanged = false;
        const nextState = {};

        for (let i = 0; i < finalReducerKeys.length; i++) {
            const key = finalReducerKeys[i];
            const reducer = finalReducers[key];
            const previousStateForKey = state[key];
            const nextStateForKey = reducer(previousStateForKey, action);

            nextState[key] = nextStateForKey;
            hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
        }

        hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;

        return hasChanged ? nextState : state;
    }
}

总结:

Redux 其实就是运用了发布订阅模式对数据对象进行管理的函数