你是原生Redux用户?有没有觉得写Redux太繁琐了?你是dvaJS用户?有没有觉得redux-saga概念太多,且yield无法返回TS类型?试试react-coat吧:项目地址:https://github.com/wooline/react-coat// 仅需一个类,搞定 action、reducer、effect、loadingclass ModuleHandlers extends BaseModuleHandlers { @reducer protected putCurUser(curUser: CurUser): State { return {…this.state, curUser}; } @reducer public putShowLoginPop(showLoginPop: boolean): State { return {…this.state, showLoginPop}; } @effect(“login”) // 使用自定义loading状态 public async login(payload: {username: string; password: string}) { const loginResult = await sessionService.api.login(payload); if (!loginResult.error) { this.updateState({curUser: loginResult.data}); Toast.success(“欢迎您回来!”); } else { alert(loginResult.error.message); } } // uncatched错误会触发@@framework/ERROR,监听并发送给后台 @effect(null) // 不需要loading,设置为null protected async ["@@framework/ERROR"](error: CustomError) { if (error.code === “401”) { this.dispatch(this.actions.putShowLoginPop(true)); } else if (error.code === “301” || error.code === “302”) { this.dispatch(this.routerActions.replace(error.detail)); } else { Toast.fail(error.message); await settingsService.api.reportError(error); } } // 监听自已的INIT Action,做一些异步数据请求 @effect() protected async “app/INIT” { const [projectConfig, curUser] = await Promise.all([ settingsService.api.getSettings(), sessionService.api.getCurUser() ]); this.updateState({ projectConfig, curUser, }); }}react-coat 特点集成 react、redux、react-router、history 等相关框架仅为以上框架的糖衣外套,不改变其基本概念,无强侵入与破坏性结构化前端工程、业务模块化,支持按需加载同时支持 SPA(单页应用)和 SSR(服务器渲染)使用 typescript 严格类型,更好的静态检查与智能提示开源微框架,源码不到千行,几乎不用学习即可上手与 Dva 的异同引入 ActionHandler 观察者模式,更优雅的处理模块之间的协作去除 redux-saga,使用 async、await 替代,简化代码的同时对 TS 类型支持更全面原生使用 typescript 组织和开发,更全面的类型安全路由组件化、无 Page 概念、更自然的 API 和更简单的组织结构更大的灵活性和自由度,不强封装脚手架等支持 SPA(单页应用)和 SSR(服务器渲染)快速切换,支持模块异步按需加载和同步加载快速切换差异示例:使用强类型组织所有 reducer 和 effect// Dva中常这样写dispatch({ type: ‘moduleA/query’, payload:{username:“jimmy”}} })//本框架中可直接利用ts类型反射和检查:this.dispatch(moduleA.actions.query({username:“jimmy”}))差异示例:State 和 Actions 支持继承// Dva不支持继承// 本框架可以直接继承class ModuleHandlers extends ArticleHandlers<State, PhotoResource> { constructor() { super({}, {api}); } @effect() protected async parseRouter() { const result = await super.parseRouter(); this.dispatch(this.actions.putRouteData({showComment: true})); return result; } @effect() protected async ModuleNames.photos + “/INIT” { await super.onInit(); }}差异示例:在 Dva 中,因为使用 redux-saga,假设在一个 effect 中使用 yield put 派发一个 action,以此来调用另一个 effect,虽然 yield 可以等待 action 的派发,但并不能等待后续 effect 的处理:// 在Dva中,updateState并不会等待otherModule/query的effect处理完毕了才执行effects: { * query (){ yield put({type: ‘otherModule/query’,payload:1}); yield put({type: ‘updateState’, payload: 2}); }}// 在本框架中,可使用awiat关键字, updateState 会等待otherModule/query的effect处理完毕了才执行class ModuleHandlers { async query (){ await this.dispatch(otherModule.actions.query(1)); this.dispatch(thisModule.actions.updateState(2)); }}差异示例:如果 ModuleA 进行某项操作成功之后,ModuleB 或 ModuleC 都需要 update 自已的 State,由于缺少 action 的观察者模式,所以只能将 ModuleB 或 ModuleC 的刷新动作写死在 ModuleA 中:// 在Dva中需要主动Put调用ModuleB或ModuleC的Actioneffects: { * update (){ … if(callbackModuleName===“ModuleB”){ yield put({type: ‘ModuleB/update’,payload:1}); }else if(callbackModuleName===“ModuleC”){ yield put({type: ‘ModuleC/update’,payload:1}); } }}// 在本框架中,可使用ActionHandler观察者模式:class ModuleB { //在ModuleB中兼听"ModuleA/update" action async [“ModuleA/update”] (){ …. }}class ModuleC { //在ModuleC中兼听"ModuleA/update" action async [“ModuleA/update”] (){ …. }}遵循规则:M 和 V 之间使用单向数据流整站保持单个 StoreStore 为 Immutability 不可变数据改变 Store 数据,必须通过 Reducer调用 Reducer 必须通过显式的 dispatch ActionReducer 必须为 pure function 纯函数有副作用的行为,全部放到 Effect 函数中每个 reducer 只能修改 Store 下的某个节点,但可以读取所有节点路由组件化,不使用集中式配置快速上手及 Demo本框架上手简单8 个新概念:Effect、ActionHandler、Module、ModuleState、RootState、Model、View、Component4 步创建:exportModel(), exportView(), exportModule(), createApp()3 个 Demo,循序渐进:入手:Helloworld进阶:SPA(单页应用)升级:SPA(单页应用)+SSR(服务器渲染)