前端状态管理思考与实践

📅
1 分钟阅读
·

目前已开源 rab 仓库 文档传送门

背景

过去两年我维护了多个 OA 应用,并在 Redux 基础上封装了路由、订阅器和 action 生命周期等功能,供各个 OA 系统复用。 示例如下: 注:其中的 reducers 包含 startnextthrowfinish 四个生命周期,用于减少 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,原有状态管理暴露出一些问题:

  1. 通过字符串 dispatch,例如上例中的 count.asyncMinus
  2. 整体集成方式耦合,富应用希望通过依赖注入组织各模块。
  3. 局部 UI 状态与业务建模无关;组件拆分后,若不放入统一数据源,就需要逐层传递 props,影响代码维护和阅读。
  4. 需要自行的处理

51 字 · 9 段落
ximing

Follow onGitHub

相关文章