关于 “ React 和 Vue 该用哪个” 我真的栓 Q
一、前言:我全都要
业务场景中是不是团队用什么我就用什么?
如果选择了其中一个使用,那为什么不用另一个?
这两个框架各有什么优点和无法解决的问题?
最新版本的 Vue3 已经出了一段时间了,我要不要做组内第一个吃螃蟹的勇士?
我该依据什么样的因素决定使用哪个技术栈?
旨在帮助那些对技术栈选择困难症的同学,并对 React 和 Vue 产生一定的认知
同时也适合那些只了解单一技术栈的小伙伴,可以拓展一下对不同框架的理解
二、正文:到底要啥
选型对象说明
团队的适用性
兼容性要求
使用层面对比
周边配套
跨端处理
设计思路
性能对比
心智模型
社区生态
开源代码许可协议
1. 选型对象说明
React 有函数式组件的和类组件两种写法,鉴于 class 写法较老,且这种写法不利于构建工具的 Tree-shaking,可能导致构建产物体积增加,而函数式组件的 hooks 写法更符合未来的潮流, 所以类组件在此也不做详细的介绍,只选取函数式组件写法的 React 作为对比对象。
Vue2 相较 Vue3 版本而言牢牢占据着大部分 Vue 开发者的视野,但是因为 Vue 官方已经把 Vue3 作为默认的版本,所以在此同时把 Vue2 和 Vue3 作为对比对象。
对比的内容不会涉及到具体的某个 API 的实现,也不会讲解大篇幅干涩的源码,过于详细的内容不是本文的重点,作为技术选型要从整体出发去考虑。
2. 团队的适用性
历史原因:如果你是以开发者的身份刚入职到一个新的环境,并且接手的是一个成熟的项目,处于正常迭代或者维护周期,那千万不要想着颠覆团队已有技术栈,技术栈切换就相当于重构。而这种重构面临的首要影响就是投入和产出不成正比,相信文章的读者大多也都是扑在各个业务一线上,对业务方来说,采用什么样的技术去实现他们并不关心,并且切换技术栈带来的风险、开发人力和测试回归的成本都难以评估,除非带来巨大价值,否则这也是与我们合作的上下游都难以接受的。
团队习惯:如果你是项目负责人,在抛开对框架本身进行对比的同时,要考虑的是团队成员对技术栈的熟悉程度,在大多数人都对某一项技术栈熟悉、而对另一项技术了解不深的情况下,那更为熟悉的技术栈带来的人效和产出质量,显然能帮助业务快速验证和试错。
3. 兼容性要求
PC 端:React 和 Vue 均不支持 IE8,对于个别浏览器兼容模式使用 IE 内核也可能是不支持的,具体要看使用的内核版本(IE 浏览器简直是前端界的噩梦),其他浏览器下可以放心大胆地使用了。
H5 端:React 和 Vue 2.x 均能使用。
4. 使用层面对比
React 和 Vue 都是渐进式框架,支持 script 标签直接使用,也支持在工程中通过模块化方式引入使用。
React:采用的 Jsx 在写法上更为灵活多变,属于在 Js 中增加了 HTML 语法,组件的实现思路是 All in Js,开发过程中拥有 Js 完整的生态。同时开发工具对 JSX 的支持相比于现有可用的其他 Vue 模板也比较先进 (比如,linting、类型检查、编辑器的自动完成)。
Vue:整体思路是 Template 模板语法,跟 Jsx 相比,它是在 HTML 中增加了对部分 Js 语法的支持,在灵活度上不如 Jsx,本质是模板语法无法穷举所有 Js 能力,所以笔者认为 Vue 内部使用的 slot、directive 等,也恰恰是对模板语法不够灵活所做出的一种补充,使模板语法也能完成跟 Jsx 同样的事情。模板语法也有优点,它更接近原生 HTML,对于新手上手更友好,并且在 Vue3 中,它从模版层面进行静态分析,对静态模版做标记,从而提升 diff 的效率。值得一提的是,与 React 一样,Vue 在技术上也支持 render 函数和 Jsx,但只是不是默认的而已。
共性也是有的,都是 DSL,对底层而言,虽然两者采用了不一样的方式实现,但最终都会被编译为渲染函数去执行。
下图是 Jsx 语法示例:
下图是 Template 语法示例:
HTML:React 是 Jsx,Vue 是默认的 Template,在这里不在赘述区别,同时需要指出的是,Vue3 相较 Vue2 而言,Template 下可以允许存在多个根节点,可以减少一些不必要的 DOM 层级。
JS:React 组件本身就是 JS 文件,形式采用函数组件和类组件,编程范式上更贴近面向对象 + 官方推崇的函数式。Vue2 组件是 Options Api,通过一个个配置项去实现生命周期、状态声明和逻辑开发。Vue3 对于部分逻辑处理和 Vue2 有很大区别,setup 模式下,已经和 React 越来越趋同了,编程范式是面向过程 + 函数式,官方命名为 Composition Api,可以使同一个功能逻辑更加集中。
CSS:React 的 CSS 使用方式是直接通过 Import 导入,Vue 文件中有专门处理样式的 Style 标签,值得一提的是,Vue3 内置状态驱动的动态 CSS,详细可查看官方文档 https://cn.vuejs.org/api/sfc-css-features.html。
其他思考:React 的函数式组件和 Vue3Composition Api,在 ESM 模块规范下对 Tree-shaking 更友好,更容易减少构建体积。
React 组件仅需引入即可使用。
Vue 的组件引入后需要全局或局部注册,且组件内的 Props 的要显式声明。
React 的复用主要体现在高阶组件、render props 以及 hooks,但是也有他们对应的不足。高阶组件层级过深时容易带来 props 的命名冲突、来源不明确的问题,并且额外的组件实例会有更多的内存消耗。hooks 的引入,使 React 的逻辑抽离更容易,完全修复了命名冲突,来源准确,且无额外开销,可以贯彻函数式编程的理念。但是与此同时,因为 hooks 中可能保留着组件状态,也意味着每次 React 的更新,如果不进行手动优化,不论前后数据是否有变化,每个 hook 都会重新执行,这也是底层架构上额外带来的问题。
Vue 的组件复用主要是是用 Mixin、Extend、插槽和 Vue3 的 Function API。Mixin:它和 React 的高阶组件带来的问题十分类似,响应式数据命名冲突,以及逻辑来源不明确。插槽:主要功能点是组件复用,它解决了数据命名冲突的问题,同时数据来源准确,但是也存在着额外组件实例带来的内存消耗 Function API:目前看来是较为优秀的一种逻辑复用方式,没有以上列出的所有问题,虽然和 React 的 hooks 十分相像,但是本质不同,Vue 可以追踪到数据变化,也仅在组件实例化时执行一次。
React:CSS moduleCSS in JSBEM 命名规范
Vue:官方支持 Style scopedBEM 命名规范
React 本身就是 Js 和 Jsx,并且 TS 专门开了后门给做了支持(Jsx 其实一开始没有类型支持,Tsx 的开发体验完全来自于 TS 专门针对 Jsx 制定的一整套推导机制),所以 Tsx 的类型支持也很完善。
Vue2.x 来自尤雨溪本人的回答是 “因为当初 API 的设计根本就没有考虑类型系统”,2.x 跟 TS 的整合需要借助 vue-class-component 使用类组件进行开发,所以目前 2.x 版本的 Vue 对 TS 的支持度较 React 仍有差距,但是最近随着 Vue2.7 的发布,可以使 Vue2.x 用上大部分 Vue3 的写法,也使 Vue2.x 就具备了兼容 TS 的能力。
Vue3,根据来自官方的建议,IDE 支持需用 <script setup lang="ts">+vscode+volar,一样能获得非常好的 TS 体验。
React:中规中距,案例仍然不够丰富,对于一些问题的答案需要借助社区,好在社区足够强大,属于疑难杂症的问题也能找到解决方案。
Vue:文档体验十分优秀且全面,介绍详细,几乎各种疑问均能找到答案。
5. 周边配套
路由管理
React-router 实现了核心路由功能。React-router-dom 基于 React-router 开发,加入了在浏览器运行环境下的一些功能,如使用 Link 组件在浏览器中会渲染一个 a 标签,也支持 History 和 Hash 路由模式。React-router-native 同样基于 React-router 开发,主要是集成了 React-native 运行环境下的功能。
状态管理
Redux 基础的状态管理库,引入了中间件,中间件位于视图层发出 action 后,到 reducer 之前触发,在中间件中可以执行比如日志打印、异步请求等操作。原流程:view -> action -> reducer -> store中间件流程:view -> action -> middleware -> reducer -> store
React-Redux 是 Redux 的插件库,用来简化 Redux。
Redux-thunk 用来处理异步的中间件。
Redux-saga 内部基于 generator 实现,用于管理 Redux 应用异步操作的中间件,与 thunk 不同点在于:thunk 是在 action 创建时调用,saga 是在应用启动时调用。在 saga 中,任务都是通过 yield Effects 来完成的。
Mobx 不同于 Redux 状态管理方案,使用相对简单,是以数据驱动视图,通过数据绑定,只修改数据本身即可实现视图的更新。
Vue
路由管理 Vue router:官方支持
状态管理 Vuex:官方支持
6. 跨端处理
App:在跨 App 界的一哥是 ReactNative,以下简称 RN,因为笔者没有亲自体验过,所以不做过多阐述,但是鉴于 RN 是 2015 年 4 月问世,时间不短,并且也有足够的团队使用,目前看来在前端跨端的领域成熟度已经相当高了。
小程序:对 React 支持度最好的当然是 Taro 了,一直在持续迭代中,也有来自京东凹凸实验室的背书,拥有较为稳定的产品和活跃社区,开发者可以大胆尝试,在最近迭代的 Taro3 里也添加了对 Vue3 的支持。
App:的跨端尝试中没有占据绝对地位的框架,Weex 火过一阵,但是近些年热度下降,并且在 Apache Incubator 也已退休,虽然有阿里的背书,但是随着参与者减少,加上也不断听说阿里内部逐渐放弃 Weex 的传言,Github 仓库最近一个更新也是 1 年前,前景未知,不推荐尝试。Vue 在最新的官方文档中推荐的跨端方案是 NativeScript 和 Capacitor,感兴趣的小伙伴可以自行查看。
小程序:一种较为流行的跨端方案是 Uni-app,在兼容多端小程序上有较好的体验,对 Vue2 和 Vue3 有着天然友好的支持度,并且依照评测也提供着非常不多的性能(评测链接 https://juejin.cn/post/6844904118901817351),文档体验着实是一言难尽…… 同时也支持 App 应用的开发。另一种跨端方式是 Mpvue,来自美团,从 Github 的仓库看已经很久未曾更新,也就不做推荐了。
多说几句在这里还要多啰嗦一下关于框架的跨端的个人理解,框架如果想跨端,那么在设计之初就要做核心与平台分离的设计,虚拟 DOM 就是一个非常典型的例子,它可以存储所有与 UI 的所有信息和交互逻辑,而在它上层与平台强相关的部分负责具体平台的逻辑实现,这也是典型的分层设计。
7. 设计思路
React 推崇的是单向数据流(但是也提供了方法进行双向改变),是数据不可变性,不可直接改变数据本身,而是通过 hooks 或 setState 更新数据。每次更新调用渲染函数从根节点生成新的虚拟 DOM 对比 旧虚拟 DOM,找到改变位置后进行 UI 的重渲染,这其中使用了基于链表数据结构的 Fiber 架构,在每帧渲染周期内的空闲时间进行 Diff 过程,具备可中断和可恢复的特性,以这种时间切片的方式不会阻塞主线程,以便执行更高优先级的任务,防止页面卡顿。更新流程如下图(没有画出具体细节,只包含基本流程):
Vue 是借助 ES6 的 API 拦截数据操作,分别在数据读取、设置阶段进行依赖的收集和通知,数据的依赖其实是一个个 Watcher 对象(Watcher 可能是组件、计算属性、或者 Watch 方法)。如果 Watcher 是组件的情况,则再调用组件的 render 函数生成虚拟 DOM ,与旧虚拟 DOM 做对比,进行更细粒度的 UI 更新。在这里借助依赖收集和局部的 DOM Diff,平衡了全量 DOM Diff 带来的性能影响。更新机制如下图(来自 Vue 官网):
8. 性能对比
抛开场景谈性能,就像抛开剂量谈毒性,全是瞎扯 ,所以本章节性能对比的数据皆有据可查,对比仅覆盖了一些常见场景,但未能覆盖全部场景:
框架测试用例仓库,截止到 2022 年 6 月 23 日,已有 4.6k Star,
对比数据,可根据条件筛选框架对比的结果
测试中的对比对象:React v18.0.0 和 Vuev3.2.37,不包含旧版本框架,本着框架升级带来性能提升的常规认知(反优化的案例也不是没有,但不在这做考虑),本章节默认最新版本的 React 和 Vue 在各自历史版本中拥有着最优性能。
测试使用设备配置:i7-8750H, 64 GB RAM, Fedora 36 (Linux 5.17.3, mitigations=off, Wayland)
测试使用浏览器:Chrome 102.0.5005.61 (64-bit)
其他:本章节的数据对比,是对已有结果的总结
创建列表
替换所有行
局部更新
选择行
交换行
删除行
创建多行
追加多行
删除多行结论:可以看到 Vue 在此场景中近乎完胜,尤其是交换行的情况下,Vue 更是大幅度领先。结果可查看下图,绿色表示操作所需时间更短,红色表示操作所需时间长。vanillajs 那一列指的是原生 js 下的性能数据。
加载时长:主要指标是 TTI(Time To Interactive),指从页面开始加载到页面可进行交互的时长,TTI 值越小,代表用户可以更早地操作页面,体验就越好
主线程工作时间:包含样式、布局、执行逻辑等
网络传输字节数:指加载页面中所有资源的成本
结果如下图,仍然是 Vue 的成绩较为优秀:
页面加载后的内存使用情况
运行内存,添加 1000 行后的内存使用情况
每 10 行点击更新 5 次后的内存使用情况
单击创建 1000 行 5 次后的内存使用情况
创建和清除 1000 行 5 次后的内存使用情况
结果如下图,Vue 依然胜出了:
4)聊些对比之外的话以上在运行时的对比都是以 1000 行数据为基准做参考,问各位小伙伴一个问题,如果数据量更庞大呢,5w 行或者 10w 行,再或者 50w 行?数据会有变化吗?各位可以再思考一下这个问题:那仅仅从以数据作为评测标准又是否可行呢?其实笔者不以为然,虽然 React 的数据落于下风,但是从 React 的 Fiber 架构上看,尤其涉及到超过一定数量级的虚拟 DOM 对比上,React 是具有优势的,此架构下的 Diff 不会阻塞主线程,用户对 UI 界面依然有控制权,虽然页面数据没有更新,但是对于用户的感知是相对友好的。所以笔者认为以下对比数据具有参考性,但并非是决定性的,在框架对比上还是希望各位小伙伴有多方面更理性的思考 。
9. 心智模型
乱花渐欲迷人眼:React 官方只维护了的核心库,对于状态管理、CSS 隔离方案等均交给了社区,这样做可以很大程度上提升开发者的参与度,也很容易诞生一些优秀的想法,造成社区内俨然就是一副百花齐放的繁荣景象,但是这也恰好是缺陷所在,在大型的 React 项目中,一旦缺少强约定,甚至能出现好几种状态管理和 Fetch 库,使开发者对项目维护、工具选择都出现困扰,于是 “百花争鸣” 也很容易变成 “乱花渐欲迷人眼” 了。而 Vue 则提供了核心库以外的状态管理、路由等,官方的库质量也有所保障,开发者只要无脑使用即可。
在项目优化中,由于 React 的更新特性是自根节点开始不断递归对比虚拟 dom 去查找变化,如果不进行手动优化,那么将导致每层组件都会重新调用 render,在大型项目中可能就是性能灾难,所以 React 官方提供了很多专门用于优化的 API,比如 shouldComponentUpdate、PureComponent、React.memo 等,致使在日常工作中,开发者在思考业务逻辑的同时,还要考虑性能优化,无法专注于业务本身。而 Vue 则因为天生具有依赖收集的优势,对于数据的变化更敏感和准确,开发者即使不刻意关注优化,Vue 也能提供给你不错的性能。
10. 社区生态
全球开发者使用框架占比调查,数据来源于 Stackoverflow 的 58,743 名受访者,截图中未完全列出所有看框架的排名,点击链接查看,React 相较 Vue 牢牢占据着第二把交椅。
npm 周下载量:React:15,764,543 次 Vue:3,279,362 次
在 Stackoverflow 上关于 #reactjs 标签的问题讨论有 396,378 个,而关于 #vue.js 的有 94709 个
在 Github 上,Vue 的 Star 数为 197K,已经超过 React 的 190K
另一方面,通过来自 similartech 的数据显示,React 被应用在了 1,256,598 个网站中,并仍在以每月 0.59% 的速率增长,而使用 Vue 的网站有 296,047 个,每月增长速率为 0.87%。
11. 开源代码许可协议
React 是 Facebook 的开源项目,Facebook 在 2016 年 11 月强化了 BSD 许可证和专利许可证的概念,在对许可证书授权方和被授权方而言,存在待遇上的不对等性,这就带来一个很关键的风险点:使用 React 的公司和 Facebook 一旦存在业务竞争,React 将成为 Facebook 获得诉讼胜利重要筹码,这无形之中将给竞争公司带来法务风险,虽然 React 后来把开源协议改成了 MIT,但是前车之鉴,在某些重大项目的技术栈选择上,尤其在当前国际环境的斗争中还是要慎重考虑,并充分告知本公司潜在的风险。
Vue 是由国人尤雨溪开发,软件协议为 MIT,目前在国内起码畅快使用是没问题的。
关于开源协议的解释可以查看百度百科
三、总结:做个了断
在选型前,首先是要考虑历史因素和团队现状,切换技术栈的前提是不要显著的增加上下游合作方的时间成本。
充分考虑框架的兼容性,如果不满足业务需求,再优秀也要 pass。
对于新手来说,React 过于灵活,虽然常用 API 不多,但是里面有很多设计模式和概念,在具备一定规模的项目中,新手的学习曲线一开始会比较陡,并且需要代码手动优化,同时庞大的社区中有层出不穷的优秀框架,但是在同类型库的选择上也会相对吃力,所以不推荐新手使用。但是对于具备几年经验的开发者来说,React 的灵活也恰恰是优势,再结合各种设计模式,很容易使项目更具创造性,对于维护具备一定规模的项目很有益处,这也真正能体现开发者的编程能力。
而 Vue 则恰恰相反,对新手友好,SFC 中 HTML、script、style 相互隔离的方式更符合传统的前端开发逻辑,Vue 也已提供了基本的优化,且周边框架的选型也不需要过多关注。
关于是否适合大型项目,有人说 Vue 不适合大型项目,适合大型项目的一定是 React,笔者并不这么认为,如果 Vue3 还没出,那么受制于 Vue2 的 Option Api,Vue 在大型项目中多少会有影响,主要体现在逻辑复用和代码组织上,但是 Vue3 有 setup 模式下 Composition Api 的加持,Vue 也已足够灵活,笔者认为关于 “Vue 不适合大型项目” 的论调可以休矣,在 Vue 和 React 特性越来越趋同的今天,如果依然出现这种想法,那可能更多还是 **“人” 的问题 **。这里还有一个有意思的小插曲,笔者曾经和朋友聊天聊到 Vue 和 React,谈到他对这俩框架的看法,当时他说的话令我印象很深刻,他说 “React 项目要想写好,会比同规模的 Vue 难一些,但是 React 要想写坏,那可太容易了”,截止到目前,我对这句话仍深以为然。
如果从性能上考虑,在本文的数据对比中 Vue3 要优于 React,但是之前已经说过,数据并非决定因素,尤其在带宽足够和设备性能越来越强悍的今天,很多运行时的性能问题其实在设备层面被抹平,普通业务中甚至已经不需要过多关注运行时性能了(但是保持良好的优化习惯是每个开发者的优良品质!),所以单单考虑性能,React 和 Vue,翻哪个牌子,看你心情咯。
四、参考资料(包括但不限于)
推荐阅读
你好,我是程序猿DD,10年开发老司机、阿里云MVP、腾讯云TVP、出过书创过业、国企4年互联网6年。从普通开发到架构师、再到合伙人。一路过来,给我最深的感受就是一定要不断学习并关注前沿。只要你能坚持下来,多思考、少抱怨、勤动手,就很容易实现弯道超车!所以,不要问我现在干什么是否来得及。如果你看好一个事情,一定是坚持了才能看到希望,而不是看到希望才去坚持。相信我,只要坚持下来,你一定比现在更好!如果你还没什么方向,可以先关注我,这里会经常分享一些前沿资讯,帮你积累弯道超车的资本。