生成式AI领域的最新成果都在这里!抢 QCon 展区门票 了解详情
写点什么

颠覆式前端 UI 开发框架:React

  • 2014-12-14
  • 本文字数:3330 字

    阅读完需:约 11 分钟

基于 HTML 的前端界面开发正变得越来越复杂,其本质问题基本都可以归结于如何将来自于服务器端或者用户输入的动态数据高效的反映到复杂的用户界面上。而来自 Facebook 的 React 框架正是完全面向此问题的一个解决方案,按官网描述,其出发点为:用于开发数据不断变化的大型应用程序(Building large applications with data that changes over time)。相比传统型的前端开发,React 开辟了一个相当另类的途径,实现了前端界面的高效率高性能开发。

首先,对于 React,有一些认识误区,这里先总结一下:

  • React 不是一个完整的 MVC 框架,最多可以认为是 MVC 中的 V(View),甚至 React 并不非常认可 MVC 开发模式;
  • React 的服务器端 Render 能力只能算是一个锦上添花的功能,并不是其核心出发点,事实上 React 官方站点几乎没有提及其在服务器端的应用;
  • 有人拿 React 和 Web Component 相提并论,但两者并不是完全的竞争关系,你完全可以用 React 去开发一个真正的 Web Component;
  • React 不是一个新的模板语言,JSX 只是一个表象,没有 JSX 的 React 也能工作。

1. React 的原理

在 Web 开发中,我们总需要将变化的数据实时反应到 UI 上,这时就需要对 DOM 进行操作。而复杂或频繁的 DOM 操作通常是性能瓶颈产生的原因(如何进行高性能的复杂 DOM 操作通常是衡量一个前端开发人员技能的重要指标)。React 为此引入了虚拟 DOM(Virtual DOM)的机制:在浏览器端用 Javascript 实现了一套 DOM API。基于 React 进行开发时所有的 DOM 构造都是通过虚拟 DOM 进行,每当数据变化时,React 都会重新构建整个 DOM 树,然后 React 将当前整个 DOM 树和上一次的 DOM 树进行对比,得到 DOM 结构的区别,然后仅仅将需要变化的部分进行实际的浏览器 DOM 更新。而且 React 能够批处理虚拟 DOM 的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从 A 变成 B,然后又从 B 变成 A,React 会认为 UI 不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。尽管每一次都需要构造完整的虚拟 DOM 树,但是因为虚拟 DOM 是内存数据,性能是极高的,而对实际 DOM 进行操作的仅仅是 Diff 部分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的 DOM 元素,而只需要关心在任意一个数据状态下,整个界面是如何 Render 的。

如果你像在 90 年代那样写过服务器端 Render 的纯 Web 页面那么应该知道,服务器端所要做的就是根据数据 Render 出 HTML 送到浏览器端。如果这时因为用户的一个点击需要改变某个状态文字,那么也是通过刷新整个页面来完成的。服务器端并不需要知道是哪一小段 HTML 发生了变化,而只需要根据数据刷新整个页面。换句话说,任何 UI 的变化都是通过整体刷新来完成的。而 React 将这种开发模式以高性能的方式带到了前端,每做一点界面的更新,你都可以认为刷新了整个页面。至于如何进行局部更新以保证性能,则是 React 框架要完成的事情。

借用 Facebook 介绍 React 的视频中聊天应用的例子,当一条新的消息过来时,传统开发的思路如上图,你的开发过程需要知道哪条数据过来了,如何将新的 DOM 结点添加到当前 DOM 树上;而基于 React 的开发思路如下图,你永远只需要关心数据整体,两次数据之间的 UI 如何变化,则完全交给框架去做。

可以看到,使用 React 大大降低了逻辑复杂性,意味着开发难度降低,可能产生 Bug 的机会也更少。至于 React 如何做到将原来 O(n^3) 复杂度的 Diff 算法降低到 O(n),大家可以参考这篇文章

2. 组件化的开发思路

虚拟 DOM 不仅带来了简单的 UI 开发逻辑,同时也带来了组件化开发的思想,所谓组件,即封装起来的具有独立功能的 UI 部件。React 推荐以组件的方式去重新思考 UI 构成,将 UI 上每一个功能相对独立的模块定义成组件,然后将小的组件通过组合或者嵌套的方式构成大的组件,最终完成整体 UI 的构建。例如,Facebook 的 instagram.com 整站都采用了 React 来开发,整个页面就是一个大的组件,其中包含了嵌套的大量其它组件,大家有兴趣可以看下它背后的代码。

如果说 MVC 的思想让你做到视图 - 数据 - 控制器的分离,那么组件化的思考方式则是带来了 UI 功能模块之间的分离。我们通过一个典型的 Blog 评论界面来看 MVC 和组件化开发思路的区别。

对于 MVC 开发模式来说,开发者将三者定义成不同的类,实现了表现,数据,控制的分离。开发者更多的是从技术的角度来对 UI 进行拆分,实现松耦合。

对于 React 而言,则完全是一个新的思路,开发者从功能的角度出发,将 UI 分成不同的组件,每个组件都独立封装。

在 React 中,你按照界面模块自然划分的方式来组织和编写你的代码,对于评论界面而言,整个 UI 是一个通过小组件构成的大组件,每个组件只关心自己部分的逻辑,彼此独立。这样最外层的界面的 Render 只需要如下代码:

通过这种方式,每个组件的 UI 和逻辑都定义在组件内部,和外部完全通过 API 来交互,通过组合的方式来实现复杂的功能。React 认为一个组件应该具有如下特征:

(1)可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的 UI 可以拆分成多个简单的 UI 组件;

(2)可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个 UI 场景;

(3)可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;

(4)可测试(Testable):因为每个组件都是独立的,那么对于各个组件分别测试显然要比对于整个 UI 进行测试容易的多。

3. 一个 React 组件开发的例子:Tab 选择器

上面从总体上介绍了 React 带来的全新的前端开发方法,以及其带来的影响,并没有介绍如何使用。为了让大家对其有一个具体的印象,这里实际来开发一个简单的组件:Tab 选择器。网店的产品页面通常需要这样的控件来选择产品属性,例如选择衣服的颜色。这个控件接受一个数据源展示多个 Tab 供点击,点击后就选中了某个颜色,界面通常如下图所示。

按传统方式,我们可以用如下代码来实现一个 jQuery 插件:

用 React 方式,代码如下:

通过比较可以看到,jQuery 插件方式,开发者首先需要考虑控件第一次 Render 出来时的 DOM 构建;其次,需要知道如何切换 UI 上的选中状态。

而 React 的方式,开发者仅仅需要考虑整体界面的 DOM 构建,不再需要关心局部更新,每次在一个 React 的 Component 上调用 setState 方法,都会触发 render 来重建整个界面。从开发思想的角度看,你可以认为每次数据的更新都会做整体的完全刷新。逻辑简单而直接。

如果我们再多考虑一步,控件的值不只在初始化和点击时可以设置,而且还可以通过程序动态的去设置。那么对于 jQuery 的方案而言,我们需要额外的方法和入口去做对应的 UI 更新。而对于 React 方式,则无需做任何改变,外部只需调用 setState 方法改变它的状态即可。这就是简化 UI 逻辑带来的好处。

完整的代码和演示已上传在 Github 上: https://github.com/supnate/react-tab-selector ,大家可以实际试用一下。

4. 结论

如上所述,React 是一个全新思路的前端 UI 框架,它完全接管了 UI 开发中最为复杂的局部更新部分,擅长在在复杂场景下保证高性能;同时,它引入了基于组件的开发思想,从另一个角度来重新审视 UI 的构成。通过这种方法,不仅能够提高开发效率,而且可以让代码更容易理解,维护和测试。Facebook 以这样一种方式将沉淀多年的前端开发经验和技术的积累完全开源出来,值得所有前端开发者去借鉴和学习。并且 React 在发布一年的时间里就获得了极大的关注,Github 上拥有超过 1 万的 Star,相信其对前端开发的方向,甚至 Web Component 的标准,都将产生一定的影响。

作者简介

王沛,邮件: supnate@gmail.com

关注 IT 趋势,承载前沿、深入、有温度的内容。感兴趣的读者可以搜索 ID:laocuixiabian,或者扫描下方二维码加关注。


感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014-12-14 16:11145626

评论 2 条评论

发布
用户头像
哈哈哈,我是看老师的极客时间课程来搜的
2021-03-26 13:54
回复
用户头像
2019-03-20 20:33
回复
没有更多了
发现更多内容

SAP ABAP 里存在 Java List 这种集合工具类么?CL_OBJECT_COLLECTION 了解一下

Jerry Wang

设计模式 迭代器模式 SAP abap 8月月更

python工程化配置方式

芥末拌个饭吧

8月月更

面试官:Redis Zset的实现为什么用跳表,而不用平衡树?

程序员小毕

Java redis 程序员 面试 后端

如何解决 “主节点故障恢复的自动化” 问题?

八点半的Bruce.D

开源一夏 | 使用 CSS 的水波文本动画(免费代码)

海拥(haiyong.site)

开源 8月月更

Go-Excelize API源码阅读(七)—— CopySheet(from, to int)

Regan Yue

开源 源码阅读 8月日更 8月月更

AS北京站如约而至!发布参会感想有机会获得官方周边奖励

InfoQ写作社区官方

热门活动 ArchSummit

深度解析佛萨奇,Forsage魔豹联盟系统开发方案(源码部署)

开发微hkkf5566

CCF大会腾源会专场即将召开,聚焦基础软件与开发语言未来发展

腾源会

开源 腾源会

基于 TLS 1.3的百度安全通信协议 bdtls 介绍

百度Geek说

安全

Netty进阶 -- WebSocket长连接开发

Bug终结者

8月月更

【设计模式-前端】单例模式深刻理解和实现

归子莫

前端 设计模式 js 8月月更

兴盛优选:时序数据如何高效处理?

TDengine

数据库 tdengine 时序数据库

MySQL之JDBC编程增删改查

了不起的程序猿

Java MySQL JAVA开发 java程序员

如何设计一组会出现死锁(Deadlock)的ABAP程序

Jerry Wang

操作系统 SAP abap 8月月更 ABAP死锁

TiSpark 原理之下推丨TiDB 工具分享

PingCAP

TiDB

运动健康服务场景事件订阅,让应用推送“更懂用户”

HMS Core

巧用自定义函数,文本控件秒变高速缓存

明道云

从普通程序员晋升到架构师需要掌握哪些技术,这份37W字Java高性能架构用13个章节彻底讲明白了

Java永远的神

Java 程序员 面试 程序人生 架构师

阿里云 Hologres助力好未来网校实时数仓降本增效

阿里云大数据AI技术

数据分析 数据治理 数据安全

从滴滴被罚款事件思考企业数据治理问题

墨天轮

大数据 滴滴 数据治理 数据安全

使用脚手架 快速开发 React组件 npm包 (基于TSDX)

HullQin

CSS JavaScript html 前端 8月月更

直播预告 | Authing 如何打造云原生 SaaS 产品架构?

Authing

知乎杀疯了,疯传2022Java面试八股文解析+大厂面经

程序知音

Java 程序员 java面试 后端技术 Java面试八股文

突破次元壁垒,让身边的玩偶手办在屏幕上动起来!

HMS Core

阿里架构师首发:80W字微服务架构手册GitHub上杀疯了

冉然学Java

Java 编程 程序员 架构 微服务

7月月更开奖啦!快来看看你中奖了吗?

InfoQ写作社区官方

热门活动 7月月更

分析 Flink 任务如何超过 YARN 容器内存限制

移动云大数据

Flink 平台

易观分析:银行零售业务实现智能化营销还需突破七大关键点

易观分析

零售 银行 智能化营销

有了阿里这5份Java架构师手册,学习起来轻松多了!

冉然学Java

Java 算法 java面试 性能调优实战 并发架构设计思想

开源一夏 |卷王必备学习的MyBatis-Plus用法~

叶秋学长

开源 mybaits 8月月更

颠覆式前端UI开发框架:React_Web框架_王沛_InfoQ精选文章