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 的核心功能,包括:
- Store:集中管理应用状态。
- Reducer:纯函数,负责状态更新。
- Connect:简化组件与 Store 的连接。
- Middleware:增强
dispatch
功能。 - Action Creator:抽象 Action,提高代码复用性。
Be the first to know when I post cool stuff
Subscribe to get my latest posts by email.
Thanks for signing up! Check your email to confirm your subscription.
Whoops, we weren't able to process your signup.