欢迎来到@medux之旅,我建议您按顺序阅读以下4篇文章,大约需要30分钟。为什么需要@medux@medux基本概念快速概览@medux路由@medux数据流第2部分:@medux基本概念快速概览--Github地址---8个新概念和名词假设你了解Redux或其他Flux框架,那么你应该知道Store、State、Reducer、Action和Dispatch是什么意思。没错,@medux中仍然使用它们,只是Action的概念发生了细微的变化,多了Event事件的特性。Effect我们知道,在Redux中,改变State必须通过dispatchaction来触发reducer。effect是相对于reducer而言的,也必须由dispatchaction来触发。不同之处在于:它是一个不纯函数,可以包含副作用,可以没有返回值,或者可以是异步的。它不能直接改变State,必须再次Dispatchaction来触发reducerActionHandler。我们可以简单的认为:store.dispatch(action),可以触发reducer和effect的执行。看来动作也可以看作是一个事件。Reducer和effect可以看作是事件的监听器,所以reducer和effect统称为:ActionHandler。模块我们通常按照高内聚低耦合的原则来划分模块。Module是相对独立的业务功能的集合,通常包括一个Model(用于处理业务逻辑)和一组View(用于展示数据和交互),需要注意的是:不要将UI视觉作为分工原则。上面说Model,Module包括一个模型(维护数据)和一组视图(展示交互),而model主要包括两个功能:ModuleState的定义和ActionHandler的定义。数据流从Model单向流向View,所以Model是独立的,不依赖于View。理论上,即使没有View,整个程序仍然可以由数据驱动。ModuleState和RootState系统分为多个相对独立的Module,不仅体现在文件夹目录中,还体现在State数据结构中。每个Module负责维护和管理State下的一个子节点,我们称之为ModuleState,整个State称为RootState。每个ModuleState都是Store的一级子节点,Module的名字是Key。每个Module只能修改自己的ModuleState,但可以读取其他ModuleState。每个Module修改自己的ModuleState。每个模块必须由调度动作触发。它可以监听其他Module发送的action来配合修改自己的ModuleStateView。ComponentView本质上还是一个Component,他们有一个逻辑上的区别:View是用来展示业务的,Component是用来展示交互的。获取数据,Component只能通过props传递。典型项目结构src├──assets//存放公共静态资源├──entity//存放业务实体类型定义├──common//存放公共代码├──components//存放UI公共组件├──modules│├──app//一个名为app的模块││├──assets//存放本模块的私有静态资源││├──components//存放本模块的私有资源││├──views│││├──TopNav│││├──BottomNav│││└──...││├──model.ts//定义模块模型││└──index.ts//导出模块│├──photos//另一个名为photos的模块││└──...│└──index.ts//模块配置和管理└──index.ts在入口处开始定义一个模型//定义本模块的ModuleState类型exportinterfaceStateextendsBaseModuleState{listSearch:{username:string;页码;pageSize:数字};列表项:{uid:字符串;用户名:字符串;年龄:数字}[];listSummary:{page:number;pageSize:数字;总数};loading:{searchLoading:LoadingState;};}//定义ModuleState的初始值exportconstinitState:State={listSearch:{username:null,page:1,pageSize:20},listItems:null,listSummary:null,loading:{searchLoading:LoadingState.Stop,},};//定义该模块中的所有ActionHandler类ModuleHandlersextendsBaseModuleHandlers{@reducerpublicputSearchList({listItems,listSummary}):State{return{...this.state,listItems,listSummary};}@effect('searchLoading')publicasyncsearchList(options:{username?:string;page?:number;pageSize?:number}={}){constlistSearch={...this.state.listSearch,...opti上};const{listItems,listSummary}=awaitapi.searchList(listSearch);this.dispatch(this.action.putSearchList({listItems,listSummary}));}//你可以监听其他Modules发送的动作,然后改变自己的ModuleState@effect(null)protectedasync['medux.RouteChange'](){if(this.rootState.route.location.pathname==='/list'){awaitthis.dispatch(this.action.searchList());静态和动态模块加载机制模块的加载策略通常集中在modules/index.ts配置中:import*asappfrom'modules/app';//定义模块的加载方案,同步或异步BothexportconstmoduleGetter={app:()=>{//使用import同步加载returnapp;},photos:()=>{//使用import()异步加载returnimport(/*webpackChunkName:"photos"*/'modules/photos');},};几个特别内置的Actionmedux.RouteChange:这个actionmedux会在路由改变的时候被触发。Error:thisactionmoduleName.Initwillbeautomaticallydispatchedwhenanerroriscatched:whenthemoduleisfirstloadedThisactionmoduleName.RouteParamswillbetriggered:thisactionmoduleName.Loadingwillbetriggeredwhenthemoduleroutingparameterschange:thisactionwillbetriggeredwhen模块路由参数改变时触发跟踪加载进度关于错误处理当执行过程中出现错误时,框架会自动派发一个medux.Error类型的errorAction,你可以监听这个动作来处理错误错误,例如:@effect(null)protectedasync[ActionTypes.Error](error:CustomError){if(error.code==='401'){this.dispatch(this.actions.putShowLoginPop(true));}elseif(error.code==='404'){this.dispatch(this.actions.putShowNotFoundPop(true));}else{error.message&&Toast.fail(error.message);//继续往上抛错会导致运行中断throwerror;}}RoutingstatefulState=Combine(Route)UI=Render(State)medux将routing看作是另一个类似于Redux的store,它记录了应用的实时状态,就像ReduxRedux被记录在内存中,由程序,而Route记录在浏览器地址栏中,由用户手动输入维护。例如:评论块的显示和关闭,可以使用两种方式触发:'/article/10'=>'/article/10/showComments',路由变化可以导致评论块的显示和关闭{showComments:false}=>{showComments:true},状态改变也可以达到同样的效果。控制还是国家控制?我们希望在组件中不要刻意区分,这样后面修改解决方案的时候不会触及到组件本身。你可以把路由当成另一个Store,但是这个RouteStore是可以被用户直接在地址栏修改的,本质上和用户鼠标点击的交互修改是一样的。所以准备从ReduxStore中提取部分数据放到RouteStore中,然后让用户通过URL任意修改...路由的最终目的是为了改变UI,所以无论什么路由方案,你总能解析出如下通用信息:当前路由会展示哪些视图,展示这些视图需要的参数。Medux将这些一般信息抽象为状态。至此,你可以忘掉路由,一切都是状态,一切都遵循UI=Render(State)。于是原本带有副作用的路由组件变成了普通组件://原始路由组件//现在直接变成普通组件{routeViews.adminHome?.Main&&}{routeViews.adminRole?.List&&}{routeViews.adminMember?.List&&}如何提取通用信息,如何将其转化为状态?方案有很多,我实现了一个:@medux/route-plan-a你也可以实现更多的plan-b,plan-c...CoreAPI查看CoreAPI文档demomedux-react-admin:基于@medux/react-web-router和ANTD4.x最新开发的通用后台管理系统,除了演示如何使用medux之外,还创造了很多独特的想法medux-react-ssr:forkfrommedux-react-admin,将其同构为服务器渲染,您可以看到如何快速将SinglePage(单页应用程序)转换为支持SEO的多页应用程序。继续阅读下一篇@medux路由文章