先说废话。最近在开发一个React技术栈的项目产品。我使用Dva.js来管理数据状态。作为一个资深ow玩家,看到这个名字的第一反应是————这不是ow里面的女主吗?仔细阅读了官方文档,发现开发者确实是受到了这个人物的启发,才给这个数据状态管理插件取名的。果然,大开发商都是工作休闲两不误。不会错的~学过React的同学都知道它的技术栈是非常多样和复杂的,所以每当你使用React的时候都需要引入很多的模块,所以Dva将这些用到的模块集成到了一起,比如一些需要react引入的依赖-saga/react-loger,将必须的ReactDOM.render、provider、connect包等全部省略,形成了一定的架构规范,大大提高了我们的开发效率。今天,让我们写一个文档。帮助后续开发者在实际项目中更好的使用Dva(PS:需要是基于UMI的框架,纯Dva搭建项目,可以直接看文末参考文档列表)什么是DvaDva首先是一个redux基于和redux-saga的数据流解决方案,并且为了简化开发体验,Dva还内置了react-router和fetch,所以也可以理解为一个轻量级的应用框架。在我目前的项目中,我主要使用数据状态管理的功能。嵌入了我们公司的fish框架,嵌入了主流的React开发框架UMI。使用起来非常方便。快速地。Dva设计的目的就是简化元素,降低难度,让你不用担心它是如何实现的。我们可以按照默认的规则来写,数据流是可以改变的。数据的改变通常是通过用户交互或浏览器行为(如路由跳过)。当这种行为会改变数据时,可以通过dispatch发起一个action。如果是同步行为,它会直接通过reducer改变状态。如果是异步行为(sideeffect),会先触发effects,然后流向reducers,最终改变状态。分层开发无论是Vue还是React开发,实际的大型应用都必须有严格的分层开发规范,以保证后续开发的可维护性。主要的分层结构有以下几点:Page负责直接和用户打交道:渲染页面,接受用户的操作输入,侧重于展示的交互逻辑,这里要理解无状态组件Model负责处理业务逻辑,为Page做数据、状态的读写、转换、暂存等,Dva中的模型做的是第一级操作Service,负责对接HTTP接口进行纯数据读写。基本概念namespacemodel的命名空间也是其全局状态的属性,只能使用字符串,不支持通过.创建多层命名空间。,相当于这个模型在组件中的key,通过connectthiskeyimport{connect}from'dva'添加你要导入的模型;exportdefaultconnect(({namespaceValue})=>({...namespaceValue}))(DvaComponent);state表示每次操作模型的状态数据都要作为不可变数据处理,保证每次都是一个新的对象,没有引用关系。reducer必须是具有固定输入和输出的纯函数。主要目的是修改自身的状态,接受两个参数:上一次累加运算的结果和当前要累加的值,并返回一个新的累加结果。此函数将一个集合合并为一个值。请注意,相同的输入必须产生相同的输出,它们不应该有任何副作用。而且每次计算都要用到immutabledataeffect,主要用于异步请求。接口调用等影响称为副作用。在我们的应用中,最常见的就是异步操作。它来自函数式编程的概念。之所以称为副作用,是因为它使我们的函数变得不纯。相同的输入不一定得到相同的输出。服务端的websocket连接、键盘输入、地理位置变化、历史路由变化等内部定义的函数都会被执行,执行后作为监听器处理事务。dispatchdispatch是一个用于触发动作的函数。动作是改变状态的唯一方法。但它只是描述了一种行为,而dispatch可以看作是触发这种行为的一种方式,而reducer描述的是如何改变数据。在Dva中,connect模型的组件可以通过props访问dispatch,可以调用model中的reducer或者effectsimport{connect}from'dva';consttestCom=props=>{const{dispatch}=props;constchangeValue=(id,val)=>{//调用reducer,通常是同步修改状态中的值dispatch({type:'dva/save',payload:{param:val},});//调用效果,通常发送后台请求dispatch({type:'dva/queryValue',payload:{id:id},});};return(
'helloworld'
)}exportdefaultconnect(({dva})=>({...dva}))(testCom);影响Model中函数分析最需要注意重要的是:Effects中的函数都是Generator函数yield是固定关键字,是Generator函数自带的关键字。它和*一起使用,有点像async和await。使用*表示它是一个Generator函数,每使用一个yield就告诉程序这是异步的,需要等待这个代码执行完成,同步代码不需要使用这个关键词。payload页面dispatch传递的selectDva中同名参数payload中Effects函数的固定参数,用于获取模型中的状态数据。需要注意的是state后面跟的是namespacenamespace的valueconstdata=yieldselect((state)=>state.namespaceName.valueName);callcallDva中Effects函数的第一个参数是一个异步函数,payload是一个参数,可以通过调用来执行。异步请求,由于yield的存在,实现了异步转同步方案const{data}=yieldcall(queryInterface,payload);putDva中Effects函数的固定参数可以使用Reducers或者同模型中的Effects,通过Reducers更新页面的数据,或者通过put实现Effects的嵌套使用yieldput({type:'save',payload:{...有效载荷},});开发目录由于公司的fish框架和commonUMI的umi框架对Dva做了深度继承,默认会自动挂载src/models下的模型定义。您只需要在模型文件夹中新建一个文件来添加一个模型来管理组件状态。对于一个页面文件夹下的模型也会默认挂载├─assets`静态资源`├─components`公共组件`├─config`路由和环境配置`├─constants`全局静态常量`├─locale`国际化`│├─en_US`英文配置`│└─zh_CN`中文配置`├─models`全局数据状态`*dva涉及目录*├─pages`页面目录,使用我参与开发的其中一个目录作为example`*Dva涉及到*│├─NodeConfig`NodeConfigexampledirectory`││├─c的目录omponents│││├─选择`Selectcomponentpagefile`*Dva涉及的目录*│││└─components││││├─AudienceInfo│││││├─index.js││││││指数。less││││├─黑名单│││││├─索引。....less││├─models││├─select.js`选择组件数据状态管理`*Dva中涉及的目录*││└─services├─services`全局接口配置`├─themes`全局样式theme`└─utils`jsgeneraltool`PS:树状图由`windowsshell`自带的`tree`命令生成Dva的使用方法首先定义一个简单的模型例子exportdefault{namespace:'dva',state:{id:'',value:{},},effects:{//所有effects前面必须有**queryValue({payload},{select,call,put}){constparams={id:payload.ID?有效载荷。id:yieldselect(state=>state.select.id)}const{data}=yieldcall(queryInterface,params);//queryInterface是一个定义好的后台请求接口,通常使用axios或者fetch来完成yieldput({type:'save',payload:data});},},reducers:{save(state,{payload}){return{...state,...payload,};},},订阅:{keyboardWatcher({dispatch}){key('?+up,ctrl+up',()=>{dispatch({type:'save'})});},},};然后将模型和组件绑定在一起React的Connect函数是一个curry写法import{connect}from'dva';consttestCom=props=>{const{helloWorld='helloworld'}=props;return(
{helloWorld}
)}//binding设置完成后,就可以在testCom组件中使用名为dva的模型了。exportdefaultconnect(({dva})=>({...dva}))(testCom);
CurryingCurrying就是把一个接受多个参数的函数转换成一个函数接受单个参数(PS:Scala语言中有类似的设计)//Curryingvarfoo=function(x){returnfunction(y){returnx+y}}foo(3)(4)//normal方法varadd=function(x,y){返回rnx+y;}add(3,4)Statelesscomponents创建无状态组件创建纯显示组件,只负责根据传入的props进行显示,不涉及改变状态状态的操作。在实际项目中,页面组件被写成无状态组件。它们可以通过简单的组合构建成页面或复杂的组件,多个简单的组件可以组合成一个大型的复杂应用。constNoStateComponent=props=>{const{helloWorld='helloworld'}=props;return({helloWorld}
)}exportdefaultNoStateComponent;无状态组件的优点是组件是无状态的,所以无状态组件不会有组件实例化过程,没有实例化过程也就不需要额外分配内存,所以性能会得到一定程度的提升。代码干净可读,对于大型项目的开发和维护非常有利。参考文档1————Dva官方文档参考文档2——UMI官方文档参考文档3——REACT基础笔记MODEL分层参考文档4————前端数据流方案Dva参考文档5——dva浅析(史上最全的dva使用解析)参考文档6——[dva]模型中effects函数解析参考文档7——Generator函数详解参考文档8——Reactconnect()()Doublebrackets--currying参考文档9————高级函数技巧-函数currying我是fx67ll.com,如果您发现本文有错误,欢迎在评论区讨论指正,感谢阅读!如果您喜欢本文,欢迎访问我本文的github仓库地址,并为我点个Star,谢谢~:)转发请注明参考文章地址,万分感谢!!!