阿里云飞天发布时刻,领先大模型限免,超7000万 tokens免费体验 了解详情
写点什么

More than React(一)为什么 ReactJS 不适合复杂交互的前端项目?

  • 2016-08-08
  • 本文字数:6047 字

    阅读完需:约 20 分钟

《More than React》系列的文章会一共分为五篇和一则附录。本文是第一篇,介绍用 ReactJS 开发时遇到的种种问题。后面四篇文章的每一篇将会分别详细讨论其中一个问题,以及 Binding.scala 如何解决这个问题。附录是一则指南,指引你从头一步步创建 Binding.scala 项目。

背景介绍

去年 4 月,我第一次在某个客户的项目中接触到 ReactJS 。

我发现 ReactJS 要比我以前用过的 AngularJS 简单很多,它提供了响应式的数据绑定功能,把数据映射到网页上,使我可以轻松实现交互简单的网站。

然而,随着我越来越深入的使用 ReactJS,我发现用 ReactJS 编写交互复杂的网页很困难。我希望有一种方式,能够像 ReactJS 一样简单解决简单问题。此外,还要能简单解决复杂问题。

于是我把 ReactJS 用 Scala 重新写了一个。代码量从近三万行降到了一千多行。

用这个框架实现的 TodoMVC 应用,只用了154 行代码。而用ReactJS 实现相同功能的TodoMVC,需要488 行代码

下图是用 Binding.scala 实现的 TodoMVC 应用。

这个框架就是 Binding.scala

问题一:ReactJS 组件难以在复杂交互页面中复用

ReactJS 中的最小复用单位是组件。ReactJS 的组件比 AngularJS 的 Controller 和 View 要轻量些。每个组件只需要前端开发者提供一个 render 函数,把 props 和 state 映射成网页元素。

这样的轻量级组件在渲染简单静态页面时很好用,但是如果页面有交互,就必须在组件间传递回调函数来处理事件。尤其是复杂的网页结构,往往需要多个组件层层嵌套,导致回调函数也必须在父子组件间层层传递,代码变成一团乱麻,维护就很难了。

我将在《More than React(二)组件对复用性有害?》中用原生DHTML API、ReactJS 和Binding.scala 实现同一个需要复用的页面,介绍Binding.scala 如何简单实现、简单复用复杂的交互逻辑。

问题二:ReactJS 的虚拟 DOM 算法又慢又不准

ReactJS 的页面渲染算法是虚拟 DOM 差量算法。

开发者需要提供 render 函数,根据 props 和 state 生成虚拟 DOM。然后 ReactJS 框架根据 render 返回的虚拟 DOM 创建相同结构的真实 DOM.

每当 state 更改时,ReacJS 框架重新调用 render 函数,获取新的虚拟 DOM 。然后,框架会比较上次生成的虚拟 DOM 和新的虚拟 DOM 有哪些差异,然后把差异应用到真实 DOM 上。

这样做有两大缺点:

  1. 每次 state 更改,render 函数都要生成完整的虚拟 DOM. 哪怕 state 改动很小,render 函数也会完整计算一遍。如果 render 函数很复杂,这个过程就白白浪费了很多计算资源。
  2. ReactJS 框架比较虚拟 DOM 差异的过程,既慢又容易出错。比如,假如你想要在某个 <ul> 列表的顶部插入一项 <li> ,那么 ReactJS 框架会误以为你修改了 <ul> 的每一项 <li>,然后在尾部插入了一个 <li>。

这是因为 ReactJS 收到的新旧两个虚拟 DOM 之间相互独立,ReactJS 并不知道数据源发生了什么操作,只能根据新旧两个虚拟 DOM 来猜测需要执行的操作。自动的猜测算法既不准又慢,必须要前端开发者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法或者 componentWillUpdate 等方法才能帮助 ReactJS 框架猜对。

我将在《More than React(三)虚拟DOM 已死?》中比较ReactJS、AngularJS 和Binding.scala 渲染机制,介绍简单性能高的Binding.scala 精确数据绑定机制。

问题三:ReactJS 的 HTML 模板功能既不完备、也不健壮

ReactJS 支持用 JSX 编写 HTML 模板。

理论上,前端工程师只要把静态 HTML 原型复制到 JSX 源文件中,增加一些变量替换代码,就能改造成动态页面。理论上这种做法要比 Cycle.js、Widok、ScalaTags 等框架更适合复用设计师提供的 HTML 原型。

不幸的是,ReactJS 对 HTML 的支持残缺不全。开发者必须手动把 class 和 for 属性替换成 className 和 htmlFor,还要把内联的 style 样式从 CSS 语法改成 JSON 语法,代码才能运行。这种开发方式下,前端工程师虽然可以把 HTML 原型复制粘贴到代码中,但还需要大量改造才能实际运行。比 Cycle.js、Widok、或者、ScalaTags 省不了太多事。

除此之外,ReactJS 还提供了 propTypes 机制校验虚拟 DOM 的合法性。然而,这一机制也漏洞百出。即使指定了 propTypes,ReactJS 也不能在编译前提前发现错误。只有测试覆盖率很高的项目时才能在每个组件使用其他组件时进行校验。即使测试覆盖率很高,propTypes 仍旧不能检测出拼错的属性名,如果你把 onClick 写成了 onclick,ReactJS 就不会报错,往往导致开发者额外花费大量时间排查一个很简单的 bug。

我将在《More than React(四)HTML 也可以静态编译?》中比较ReactJS 和Binding.scala 的HTML 模板,介绍Binding.scala 如何在完整支持XHTML 语法的同时静态检查语法错误和语义错误。

问题四:ReactJS 与服务器通信时需要复杂的异步编程

ReactJS 从服务器加载数据时的架构可以看成 MVVM(Model–View–ViewModel) 模式。前端工程师需要编写一个服务访问层作为 Model,把 ReactJS 的 state 当做 ViewModel,而 render 当做 View。Model 负责访问后端 API 并把数据设置到 state(即 View Model) 上,可以用 Promise 和 fetch API 实现。然后,render,即 View,负责把 View Model 渲染到页面上。

在这整套流程中,前端程序员需要编写大量闭包组成的异步流程,设置、访问状态的代码五零四散,一不小心就会 bug 丛生,就算小心翼翼的处理各种异步事件,也会导致程序变得复杂,既难调试,又难维护。

我将在《More than React(五)为什么别用异步编程?》中比较 ReactJS 和 Binding.scala 的数据同步模型,介绍 Binding.scala 如何自动同步服务器数据,避免手动异步编程。

结论

尽管 Binding.scala 初看上去很像 ReactJS,但隐藏在 Binding.scala 背后的机制更简单、更通用,与 ReactJS 和 Widok 截然不同。

所以,通过简化概念,Binding.scala 灵活性更强,能用通用的方式解决 ReactJS 解决不了的复杂问题。

比如,除了上述四个方面以外,ReactJS 的状态管理也是老大难问题,如果引入 Redux 或者 react-router 这样的第三方库来处理状态,会导致架构变复杂,分层变多,代码绕来绕去。而 Binding.scala 可以用和页面渲染一样的数据绑定机制描述复杂的状态,不需要任何第三方库,就能提供服务器通信、状态管理和网址分发的功能。

以下表格中列出了上述 Binding.scala 和 ReactJS 的功能差异:

    Binding.scala ReactJS
复用性 最小复用单位 方法 组件
复用难度 不论交互内容还是静态内容都容易复用 容易复用静态内容组件,但难以复用交互组件
页面渲染算法 算法 精确的数据绑定 虚拟 DOM
性能
正确性 自动保证正确性 需要开发者手动设置 key 属性,不然复杂的页面会错乱。
HTML 模板 语法 Scala XML 字面量 JSX
是否支持 HTML 或 XHTML 语法 完整支持 XHTML 残缺支持。正常的 XHTML 无法编译。开发者必须手动把 class 和 for 属性替换成 className 和 htmlFor,还要把内联的 style 样式从 CSS 语法改成 JSON 语法。
如何校验模板语法 自动编译时校验 运行时通过 `propTypes` 校验但无法检测简单的拼写错误。
服务器通讯 机制 自动远程数据绑定 MVVM + 异步编程
实现难度 简单 复杂
其他 如何分派网址或者锚点链接 支持把网址当成普通的绑定变量来用,无需第三方库。 不支持,需要第三方库 react-router
功能完备性 完整的前端开发解决方案 本身只包含视图部分功能。需要额外掌握 react-router 、 Redux 等第三方库才能实现完整的前端项目。
学习曲线 API 简单,对没用过 Scala 的人来说也很好懂 上手快。但功能太弱导致后期学习第三方库时曲线陡峭。
    Binding.scala ReactJS

两个多月前,我在 Scala.js 的论坛发布 Binding.scala 时,当时 Scala.js 社区最流行的响应式前端编程框架是 Widok 。Tim Nieradzik 是 Widok 的作者。他在看到我发布的框架后,称赞这个框架是 Scala.js 社区最有前途的 HTML 5 渲染框架。

他是对的,两个月后,现在 Binding.scala 已经成为 Scala.js 社区最流行的响应式前端编程框架。

Awesome Scala 网站对比了 Scala 的响应式前端编程框架,Binding.scala 的活跃程度和流行度都比 Udash、Widok 等其他框架要高。

我在最近的几个项目中,也逐渐放弃 JavaScript 和 ReactJS,改用 Scala.js 和 Binding.scala 搭建新时代的前端技术栈。

相关链接

鸣谢

感谢张凯峰和郑培真帮我检阅了这一系列文章,你看到的文章的结构和内容许多地方都来自他们提出的修改意见。

More than React 系列文章

《More than React(一)为什么ReactJS 不适合复杂交互的前端项目?》

《More than React(二)组件对复用性有害?》

《More than React(三)虚拟DOM 已死?》

《More than React(四)HTML 也可以静态编译?》

《More than React(五)异步编程真的好吗?》

作者简介

杨博是 Haxe 和 Scala 社区的活跃贡献者,发起和维护的开源项目包括  protoc-gen-as3 Stateless Future haxe-continuation Fastring Each Microbuilder Binding.scala  。杨博曾在网易任主程序和项目经理,开发过多款游戏。现在 ThoughtWorks 任 Lead Consultant,为客户提供移动、互联网、大数据、人工智能和深度学习领域的解决方案。


感谢张凯峰对本文的策划,韩婷对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-08-08 17:3816183

评论

发布
暂无评论
发现更多内容

阿里架构师剖析程序运行原理,程序是如何运行又是如何崩溃的?

Java 程序员 后端

阿里腾讯微软拥抱低代码,程序员们要“失业”?

Java 程序员 后端

震撼发布!阿里老兵亲手操刀微服务架构实战,整理出140个案例

Java 程序员 后端

面试太难?技术面考察太底层?二面被拒到收割阿里架构offer,复盘成功经历分享!

Java 程序员 后端

阿里面试官整理出面试必问:java面试核心知识原理+框架笔记

Java 程序员 后端

阿里面试官:就说最后一遍,有关Spring这13点我们必问!

Java 程序员 后端

面试官最喜欢问的Spring Boot知识点整理【附解答】(下)

Java 程序员 后端

阿里程序员:入职才两个月,我决定离职

Java 程序员 后端

阿里老人吐槽:新人水平差不服管不加班!汇报经理让他无法转正

Java 程序员 后端

这几个动态规划的问题,面试官就爱问

华为云开发者联盟

数组 动态规划 序列 子数组 公共子串

阿里面试官:HashMap 为什么是线程不安全的?

Java 程序员 后端

阿里面试官:你好,谈谈对Synchronized的理解?(一

Java 程序员 后端

面试前夕,你一定要先来看看阿里和京东都问些啥!(阿里+京东Java岗面试题概要

Java 程序员 后端

面试大厂一定离不开的——ThreadLocal,它的实现原理你知道吗

Java 程序员 后端

面试官求你别再问我hook了

CRMEB

阿里蚂蚁金服超全126道面试题,都会的话,你也能去面阿里了

Java 程序员 后端

阿里面试确实严格,面了整整5轮,还好我技高一筹!

Java 程序员 后端

震惊!2022 年秋招 Java 后端开发岗竟然一片红海!算法岗都不香了吗?

Java 程序员 后端

靠谱,这是我见过最好的编程指南了!赶快收藏吧,错过大学就白上了!

Java 程序员 后端

教你如何用Keras搭建分类神经网络

华为云开发者联盟

神经网络 keras 分类神经网络 MNIST 数字图像

面试字节、阿里等大厂后,总结了今年的Java面试必问的微服务面试题(含答案)

Java 程序员 后端

阿里技术总监纯手打的内部手册《MySQL笔记》真是太硬核了

Java 程序员 后端

阿里老人吐槽:新人水平差不服管不加班!汇报经理让他无法转正(1)

Java 程序员 后端

Flink CDC 实时数据同步详细解析

五分钟学大数据

flink 11月日更

道与术丨华为云数据库战略启示录

华为云开发者联盟

数据库 opengauss 华为云 GaussDB 战略

面向对象知识点整理

Java 程序员 后端

面向对象设计的九大基本原则 (GRASP)

Java 程序员 后端

面向对象-抽象性思想(知识整理)

Java 程序员 后端

面试中常见的问题总结

Java 程序员 后端

面试官一口气问了MySQL事务、锁和MVCC,

Java 程序员 后端

面试官再问分布式事务,求你看完这份至尊级分布式笔记,给年轻的面试官上一课

Java 程序员 后端

More than React(一)为什么ReactJS不适合复杂交互的前端项目?_JavaScript_杨博_InfoQ精选文章