Redux-實現createStore

Neeky Ceng發表於2020-07-20

最近在讀Redux原始碼,現將自己實現的程式碼和理解貼上,後期再補充詳細~

/**
 * 判斷某個物件是否是一個plain-object
 * @param {*} obj 
 */
function isPlainObject(obj) {
    if (typeof obj !== "object") {
        return false;
    }
    return Object.getPrototypeOf(obj) === Object.prototype;
}

/**
 * 得到一個指定長度的隨機字串
 * @param {*} length 
 */
function getRandomString(length) {
    return Math.random().toString(36).substr(2, length).split("").join(".")
}

/**
 * 實現createStore的功能
 * @param {*} reducer 接收reducer處理器
 * @param {*} defaultState 初始化的狀態值
 */
export function createStore(reducer, defaultState, enhancer) {
    // 判斷是否傳入defaultState
    if (typeof defaultState === 'function' && typeof enhancer === 'undefined') {
        enhancer = defaultState
        defaultState = undefined
    }
    // 判斷是否傳入enhancer且為函式
    if (typeof enhancer !== 'undefined') {
        if (typeof enhancer !== 'function') {
            throw new Error('Expected the enhancer to be a function.')
        }
        return enhancer(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: `@@redux/INIT${getRandomString(7)}`
    });

    return {
        dispatch,
        getState,
        subscribe
    }
}

 

相關文章