React@16.x(56)Redux@4.x(5)- 实现 createStore

1,分析

createStore(),参数1为 reducer,参数2为初始化的 state(中间件参数,之后的文章会介绍)。返回的 store 对象有以下属性:

  • dispatch 方法,用于分发 action
  • getState 方法,用于得到最新的 state
  • subscribe 方法,用于在 state 发生变化时执行。

2,实现

2.1,基础实现

export const createStore = (reducer, defaultState) => {
    let currentReducer = reducer;
    let currentState = defaultState;
    let listeners = [];

    const dispatch = (action) => {
        currentState = currentReducer(currentState, action);
        // 每次更新时,遍历监听器。
        for (const listener of listeners) {
            listener();
        }
    };

    const getState = () => {
        return currentState;
    };

    const subscribe = (listener) => {
        listeners.push(listener);
        // 取消监听
        return () => {
            listeners = listeners.filter((f) => f !== listener);
        };
    };

    // createStore 创建时会调用一次。
    dispatch({
        type: "@@redux/INITg.p.0.c.e.f",
    });

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

2.2,优化

2.2.1,随机字符串

createStore 创建时调用 dispatch() 传入的 type 是随机 36位 字符串。可以这样生成:

Math.random().toString(36) // '0.ge0p9nwtid7'
Math.random().toString(36).substring(2, 8) // 'ge0p9n'
Math.random().toString(36).substring(2, 8).split('').join('.') // 'g.e.0.p.9.n'
export const createStore = (reducer, defaultState) => {
    // ...
    dispatch({
        type: `@@redux/INIT${getRandomString()}`,
    });
	// ...
};

function getRandomString() {
    return Math.random().toString(36).substring(2, 8).split('').join('.')
}

2.2.2,action 的判断

action 有一些限制

  • 必须是一个平面对象。
  • 必须有 type 属性。
const dispatch = (action) => {
    if (typeof action !== "object" || Object.getPrototypeOf(action) !== Object.prototype) {
        throw new Error("action 必须是一个 plain Object");
    }
    if (action.type === undefined) {
        throw new Error("action 必须有 type 属性");
    }
   // ...
};

2.2.2,监听器的优化

监听器返回的函数执行一次之后,再次执行时应该立即返回且什么都不做。因为对应的监听器已经卸载了。

const subscribe = (listener) => {
    listeners.push(listener);
    let isRemove = false;
    return () => {
        if (isRemove) {
            return;
        } else {
            isRemove = true;
            listeners = listeners.filter((f) => f !== listener);
        }
    };
};

2.3,最终形态

export const createStore = (reducer, defaultState) => {
    let currentReducer = reducer;
    let currentState = defaultState;
    let listeners = [];

    const dispatch = (action) => {
        if (typeof action !== "object" || Object.getPrototypeOf(action) !== Object.prototype) {
            throw new Error("action 必须是一个 plain Object");
        }
        if (action.type === undefined) {
            throw new Error("action 必须有 type 属性");
        }
        currentState = currentReducer(currentState, action);
        // 每次更新时,遍历监听器。
        for (const listener of listeners) {
            listener();
        }
    };

    const getState = () => {
        return currentState;
    };

    const subscribe = (listener) => {
        listeners.push(listener);
        let isRemove = false;
        // 取消监听
        return () => {
            if (isRemove) {
                return;
            } else {
                isRemove = true;
                listeners = listeners.filter((f) => f !== listener);
            }
        };
    };

    // createStore 创建时会调用一次。
    dispatch({
        type: `@@redux/INIT${getRandomString}`,
    });

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

function getRandomString() {
    return Math.random().toString(36).substring(2, 8).split("").join(".");
}

2.4,关于 applyMiddleware 的补充代码

参考 实现 applyMiddleware


以上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下雪天的夏风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值