Regular的Redux实现整理

在 React 或其他框架中,组件的树形结构可能导致数据传递变得复杂,甚至出现“数据传递黑洞”。Redux 通过引入一个全局的状态管理机制解决了这一问题。以下是 Redux 的核心实现原理及其逐步改进的过程。

1. 数据传递问题 🔗︎

问题描述 🔗︎

组件的树形结构决定了数据的流向,导致深层次组件之间的数据传递变得困难,容易形成“数据传递黑洞”。

解决方案 🔗︎

通过中介者(Store)来集中管理共享数据,所有组件都通过 Store 获取或修改数据。


2. 初步实现:简单的 Store 🔗︎

中介者的实现 🔗︎

(function createStore() {
    var store;
    return function() {
        if (!store) {
            store = new Regular();
        }
        return store;
    };
})();

组件 A 修改数据 🔗︎

define(['./store.js'], function(createStore) {
    var A = Regular.extend({
        name: "组件A",
        data: {
            title: '标题'
        },
        getData: function() {
            this.data.title = createStore().data.title;
        },
        setData: function() {
            store.data.title = '新标题';
            // 通知所有其他组件
            store.$emit('change', {
                title: '新标题'
            });
        }
    });
    return A;
});

其他组件监听数据 🔗︎

define(['./store.js'], function(store) {
    var B = Regular.extend({
        name: "组件B",
        init: function() {
            createStore().$on('change', function(newTitle) {
                this.data.title = newTitle;
            });
        }
    });
    return B;
});

3. 改进 1:分离数据与 Store 🔗︎

为了防止直接访问和修改 store.data,我们将数据与 Store 分离,并通过接口获取数据。

(function createStore() {
    var store;
    return function() {
        if (!store) {
            var store = new Regular();
            var state = {};
            store.getState = function() { return state; };
            store.subscribe = function(listener) { store.$on('change', listener); };
            store.dispatch = function(action) {
                if (action.type == 'changeTitle') {
                    state.title = action.data.title;
                }
                store.$emit('change', state);
            };
        }
        return store;
    };
})();

4. 改进 2:引入 Reducer 🔗︎

将数据处理逻辑从 Store 中抽离出来,使用 Reducer 来管理状态更新。

(function createStore(reducer, initState) {
    var store;
    return function() {
        if (!store) {
            var store = new Regular();
            var state = initState;
            store.getState = function() { return state; };
            store.subscribe = function(listener) { store.$on('change', listener); };
            store.dispatch = function(action) {
                state = reducer(state, action);
                store.$emit('change', state);
            };
        }
        return store;
    };
})();

Reducer 示例:

function reducer1(state, action) {
    switch (action.type) {
        case 'CHANGE_TITLE':
            return Object.assign({}, state, { title: action.data.title });
        default:
            return state;
    }
}

5. 改进 3:顶层容器与组件扩展 🔗︎

为了让组件更方便地使用 Store,我们创建了一个顶层容器 StoreProvider,并扩展了组件的能力。

const App = Regular.extend({
    name: 'App',
    template: `
        <StoreProvider store={store}>
            <A />
            <B />
        </StoreProvider>
    `,
    config(data) {
        data.store = createStore(reducers, { title: "标题" });
    }
});

var StoreProvider = Regular.extend({
    template: '{#include this.$body}',
    config: function(data) {
        this.store = data.store;
    },
    modifyBodyComponent: function(component) {
        component.dispatch = this.store.dispatch.bind(this.store);
        this.store.subscribe(function() {
            var state = this.store.getState();
            component.mapState(state);
        }.bind(this));
    }
});

6. 改进 4:Connect 函数 🔗︎

为了避免每个组件都需要手动实现 mapState 方法,我们抽取了一个 connect 函数。

function connect(config, Component) {
    Component.implement({
        mapState: function(state) {
            const mappedData = config.mapState.call(this, state);
            mappedData && Object.assign(this.data, mappedData);
        }
    });
}

connect({
    mapState: function(state) {
        return {
            title: state.title
        };
    }
}, B);

7. 中间件的实现 🔗︎

中间件用于在 dispatch 方法中插入额外的逻辑,例如日志记录。

初步实现 🔗︎

function applyMiddleware(middleware) {
    let store = createStore(reducer1, initState);
    let dispatch = function(action) {
        middleware(store.dispatch, action);
    };
    return Object.assign({}, store, { dispatch: dispatch });
}

改进 1:支持多个中间件 🔗︎

function applyMiddlewares(...middlewares) {
    let store = createStore(reducer1, initState);
    let dispatch = middlewares.reduceRight((dispatch, middleware) => {
        return middleware(dispatch);
    }, store.dispatch);
    return Object.assign({}, store, { dispatch: dispatch });
}

中间件示例 🔗︎

function logger(next) {
    return function(action) {
        console.log("before dispatch");
        next(action);
        console.log("after dispatch");
    };
}

8. Action Creator 🔗︎

Action Creator 是对 dispatch 参数的一种抽象,便于复用。

const CHANGE_TITLE = 'CHANGE_TITLE';

function changeTitle(newTitle) {
    return {
        type: CHANGE_TITLE,
        data: { title: newTitle }
    };
}

this.$dispatch(changeTitle('新标题'));

总结 🔗︎

通过以上步骤,我们实现了 Redux 的核心功能,包括:

  1. Store:集中管理应用状态。
  2. Reducer:纯函数,负责状态更新。
  3. Connect:简化组件与 Store 的连接。
  4. Middleware:增强 dispatch 功能。
  5. Action Creator:抽象 Action,提高代码复用性。

Redux 架构图