背景
过去两年我维护了多个 OA 应用,并在 Redux 基础上封装了路由、订阅器和 action 生命周期等功能,供各个 OA 系统复用。
示例如下:
注:其中的 reducers 包含 start、next、throw、finish 四个生命周期,用于减少 Redux 异步处理的样板代码。
import React from 'react';
import rab, {connect, createModel, put, call} from 'rab';
import {Router, Route} from 'rab/router';
function stop(time) {
return new Promise((res, rej) => {
setTimeout(function () {
res();
}, 2000);
});
}
const app = rab();
// 2. Model
let count = createModel({
namespace: 'count',
state: {
num: 0,
loading: false
},
reducers: {
add(state, action) {
console.log(action.payload);
return Object.assign({}, state, {num: state.num + 1})
},
asyncAdd(state, action) {
return Object.assign({}, state, {num: state.num + action.payload})
},
asyncMinus: {
start(state, action){
return Object.assign({}, state, {loading: true});
},
next(state, action){
return Object.assign({}, state, {num: state.num + action.payload})
},
throw(state, action){
return Object.assign({}, state, {num: state.num + action.payload})
},
finish(state, action){
return Object.assign({}, state, {loading: false});
}
}
},
actions: {
asyncAdd: (a, b, c) => async ({getState, dispatch}) => {
await stop();
return 100;
},
async asyncMinus() {
await stop();
return -100;
}
},
subscriptions: {
init({history, dispatch}){
history.listen((location) => {
console.log('init------------>', location)
})
}
}
})
app.addModel(count);
// 3. View
const App = connect(({count}) => ({
count
}))((props) => {
return (
<div>
<h2>{ props.count.num }</h2>
<h2>{ !props.count.loading ? 'finish' : 'loading' }</h2>
<button key="add" onClick={() => {
put({type: 'count.add', payload: {a: 1}});
}}>+
</button>
<button key="asyncadd" onClick={() => {
props.dispatch(count.actions.asyncAdd());
}}>ASYNC ADD
</button>
<button key="asyncminus" onClick={() => {
put({type: 'count.asyncMinus', payload: {a: 1, n: 2}});
}}>ASYNC Minus
</button>
</div>
);
});
// 4. Router
app.router(({history}) => {
return (
<Router history={history}>
<Route path="/" component={App}/>
</Router>
);
});
// 5. Start
app.start('#demo_container');问题
今年开始,我主要负责实时协作的 Excel、Word、PPT、脑图等大象富应用。为便于后续维护,项目改用 TypeScript,原有状态管理暴露出一些问题:
- 通过字符串 dispatch,例如上例中的
count.asyncMinus。 - 整体集成方式耦合,富应用希望通过依赖注入组织各模块。
- 局部 UI 状态与业务建模无关;组件拆分后,若不放入统一数据源,就需要逐层传递 props,影响代码维护和阅读。
- 需要自行的处理
