React 是当前最火的前端框架,但 React 只是一个 View 层,需要搭配 Redux 等库才会在大型项目里面发挥作用。
业务代码一直是我们写项目时的痛点,这里是笔者工作几年来对 React 在业务层面的一些思考和实践。
主要内容:
- 什么是 MVC
- 代码的组织与分层
- 数据的管理
- 介绍 React-imvc 框架
-
-
- 前言
- 什么是 MVC
- 代码的组织与分层
- Service
- formatter
- MVC
- 其他
- 数据的管理
- React-IMVC
- 安装
- npm scripts
- 添加 src 目录和路由文件
- 编写每个页面的 MVC 结构
- 总结
-
前言
在前端全面拥抱框架之后,很多人都产生了一种误解,认为使用框架就会少写原生 JS,降低了 JS 的使用能力。但不管是什么框架,对于业务代码来说,最终还是要用原生 JS 来写的。
如何写出可维护和可读性高的代码,也一直是一个困扰很多人的问题,这里只介绍如何写好 React 中的业务代码,至于一些优化小技巧,推荐去看《代码大全 2》和《编写可读代码的艺术》。
什么是 MVC
你可能会问,不是讲 React 吗么又扯到了 MVC 身上想起来之前在某技术 站,有个人反驳我说 React 推崇函数式编程,你怎么又倒退回了面向对象和 MVC回应说 MVC 是一种架构,函数式编程是一种思想,两者并没有冲突。
那么是什么 MVC 呢信大家都对 MVC 比较熟悉了,我这里引用一下维基百科的解释:
MVC 模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
MVC 模式最早由 Trygve Reenskaug 在 1978 年提出,是施乐帕罗奥多研究中心(Xerox PARC)在 20 世纪 80 年代为程序语言 Smalltalk 发明的一种软件架构。MVC 模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。专业人员可以通过自身的专长分组:
- 控制器(Controller):负责转发请求,对请求进行处理。
- 视图(View):界面设计人员进行图形界面设计。
- 模型(Model):程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计 (可以实现具体的功能)。
下面这是一些分层后一个简单的目录结构。
Service
统一管理所有请求路径,并且将页面中涉及到的 络请求封装为 class。
这样带来的好处就是,很清楚的知道页面中涉及了哪些请求,如果使用了 TypeScript,后续某个请求方法名修改了后,在所有调用的地方也会提示错误,非常方便。
formatter
formatter 层会储存一些用于格式化数据的方法,这些方法可以接收数据,返回新的数据,这里面不应该再涉及到其他的逻辑,这样有利于单元测试。单个 format 函数也不应该格式化过多数据,函数应该根据功能进行适当拆分,合理复用。
MVC
正如我们前面所说的一样,以 React 作为 view 层,Redux 作为 model 层,那么 controller 应该就是处理各种副作用操作( 络请求、缓存、事件响应等)的地方。
当处理一个请求的时候,controller 会调用 service 里面对应的方法,拿到数据后再调用 formatter 的方法,将格式化后的数据存入 store 中,展示到页面上。
这里建议尽量用纯函数组件,当然有些涉及到业务逻辑的组件依然可以使用 class 组件。有了 hooks 之后,React 组件也会变得更加纯粹。
对于 React 应用来说,最外层的组件一般称作容器组件,我们会在容器组件里面进行 络请求、连接 store 等副作用的操作。
在这里,容器组件里面的一些逻辑也可以剥离出来放到 controller 中(React-IMVC 就是这种做法),这样就可以给 controller 赋予生命周期,容器组件也只用于纯展示。
我们将容器组件的生命周期放到 wrapper 这个高阶组件中,并在里面调用 controller 里面封装的生命周期,这样我们可以就编写更加纯粹的 view,例如:
wrapper.js
view.js
controller.js
其他
对于埋点来说,原本也应该放到 controller 中,但也是可以独立出来一个 tracelog 层,至于 tracelog 层如何实现和调用,还是看个人爱好,我比较喜欢用发布订阅的形式。
如果还涉及到缓存,那我们也可以再封装一个 storage,这里存放对缓存进行增删查改的各种操作。
对于一些常用的固定不变的值,也可以放到 constants.js,通过引入 constants 来获取值,这样便于后续维护。
数据的管理
不过也不代表着只要分层就万事大吉,分层只能够保证代码文件结构上的清晰。真正想写出好的业务代码,最重要的还是你对业务逻辑的理解足够清晰,页面上的数据流动是怎样的据结构怎么设计更加合理面上涉及到了哪些交互些交互会带来哪些影响/p>
以如下携程的酒店列表页为例,这个页面看似简单,实际上包含了很多复杂的交互。
上方的是四个筛选项菜单,点开后里面包含了很多子类筛选项,比如筛选里面包括了双床、大床、三床,价格/星级里面包含了高档/豪华、¥150~300 等。
下方是快捷筛选项,对应了部分筛选项菜单里面的子类筛选项。
我借助这个例子来说明,在开始写页面之前,一定要对页面中的隐藏交互和数据流动很熟悉,也需要去设计更加合理的数据结构。
对于深层次的列表结构,键值对会比数组查询速度更快,通过 key 也会更容易和其他数据进行联动,但是却不能保证顺序,有时候可能就需要牺牲空间来换时间。
当我们选中大床的时候,只需要保存“1-1”这个 key,再和 store 中快捷筛选项列表里面的 key 进行 mapping(快捷筛选项里面的项也应该格式化为 {‘type-id’: filterItem} 的键值对格式),这样从时间复杂度上说,比直接遍历两个数组更高效。
在设计 store 的时候应当尽量使用扁平化的数据结构,这样有利于提高查询的效率,也提高了可读性。
React-IMVC
React-IMVC 是携程度假研发部的工业聚大佬开源的一个同构框架,目前已经在部门里面大量使用。
前面实现的简单分层,就是 React-IMVC 的设计思想,当然 React-IMVC 做的事情更多,包括了服务端渲染、路由、状态管理等等,这是一整套解决方案。
引用一个 React-IMVC 的官方文档介绍:
MVC 三者都是 Isomorphic,既是服务端 MVC,也是浏览器端 MVC。
React-IMVC 是 Isomorphic MVC 的 React 实现,它是一个 Web 框架。通过 React-IMVC,我们可以更便利地实现同构 Web 应用的开发。
这里通过实现一个简单的加减器来探索 React-IMVC 的使用方法。
安装
首先,我们需要通过 npm 或者 yarn 来安装 React-IMVC 的相关依赖。
npm scripts
在你的 package.json 里添加 npm scripts 如下命令:
添加 src 目录和路由文件
在 package.json 所在的目录下,新建一个名称为 src 的文件夹。
在 src 文件夹里新增 index.js 入口文件,添加相关的路由配置。
编写每个页面的 MVC 结构
每个页面必须是一个包含 controller.js 的文件夹,其中 controller.js 是页面的入口文件。
很明显这里以 controller 为入口,引入了 model 来初始化 store,引入 view 作为视图入口。
React-IMVC 使用了一个类 Redux 的状态管理库——Relite,写法和 Redux 有一些不同。
剩下的就是页面视图的入口了,这里和 React 组件的写法并无区别,只是接受了 state 和 handlers 两个参数。
通过这个简单的例子,我们可以看出来 React-IMVC 使用起来很方便,基本上没有引入新的概念,包括服务端渲染也可以一键设置。
有兴趣的可以去看一下具体的文档:React-IMVC。
总结
在开始写业务之前,理应先想清楚需求和业务逻辑,设计出合理的数据结构,对代码进行好的分层,这样在一定程度上才可以写出可维护性更高的代码。
阅读全文: http://gitbook.cn/gitchat/activity/5cf3eb2ac4e17757d9a2edef

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!