上一小节,我们把 reducer 按组件维度拆分了,通过 combineReducers 合并了起来。但是还有个问题, state 我们还是写在一起的,这样会造成 state 树很庞大,不直观,很难维护。我们需要拆分,一个 state,一个 reducer 写一块。

    这一小节比较简单,我就不卖关子了,用法大概是这样(注意注释)

    1. /* counter 自己的 state 和 reducer 写在一起*/
    2. let initState = {
    3. count: 0
    4. }
    5. function counterReducer(state, action) {
    6. /*注意:如果 state 没有初始值,那就给他初始值!!*/
    7. if (!state) {
    8. state = initState;
    9. }
    10. switch (action.type) {
    11. case 'INCREMENT':
    12. return {
    13. count: state.count + 1
    14. }
    15. default:
    16. return state;
    17. }
    18. }

    我们修改下 createStore 函数,增加一行 dispatch({ type: Symbol() })

    1. const createStore = function (reducer, initState) {
    2. let state = initState;
    3. let listeners = [];
    4. function subscribe(listener) {
    5. listeners.push(listener);
    6. }
    7. function dispatch(action) {
    8. state = reducer(state, action);
    9. for (let i = 0; i < listeners.length; i++) {
    10. const listener = listeners[i];
    11. listener();
    12. }
    13. }
    14. function getState() {
    15. return state;
    16. }
    17. /* 注意!!!只修改了这里,用一个不匹配任何计划的 type,来获取初始值 */
    18. dispatch({ type: Symbol() })
    19. return {
    20. subscribe,
    21. dispatch,
    22. getState
    23. }
    24. }

    我们思考下这行可以带来什么效果?

    1. createStore 的时候,用一个不匹配任何 type 的 action,来触发 state = reducer(state, action)

    2. 因为 action.type 不匹配,每个子 reducer 都会进到 default 项,返回自己初始化的 state,这样就获得了初始化的 state 树了。

    你可以试试

    1. /*这里没有传 initState 哦 */
    2. const store = createStore(reducer);
    3. /*这里看看初始化的 state 是什么*/
    4. console.dir(store.getState());

    本小节完整源码见 demo-4

    到这里为止,我们已经实现了一个七七八八的 redux 啦!