为什么我们放弃了 Vue?Vue 和 React 深度对比

原文:为什么我们放弃了 Vue?Vue 和 React 深度对比
经作者授权转载

我使用 Vue 和 React 已经很长一段时间了,两个框架上实践代码量都在 10 万行以上。不得不说两者都是很 nice 的,帮助开发者减少很多工作量,这类框架是现代化前端开发必备的。然而 Vue 和 React 两者之间的选择并不像选择苹果或香蕉一样简单,两者在工程实践上的差距让我们逐渐放弃了 Vue。本文以不一样的角度对两者进行深度对比。

为什么我们放弃了 Vue?Vue 和 React 深度对比_第1张图片

常见摇摆问题、观点

首先,我简短谈谈常见对比项目、观点的看法,这些部分内容可以通过一些文章或者 Vue 官方对比文档查到,主要目的是帮助小白解决入门摇摆问题。我会根据长期实践经验直接下结论,如果你反对,欢迎评论区留言 battle,反正我不会回答你这类问题。

Vue 或 React 文档更丰富?

两者都有丰富的文档(包括中文文档),Vue 文档React 中文,所以不用担心你四六级都过不了,看不懂文档,这都是有眼就行的事~当然,如果你提前懂点 javascript 相关知识也是大大滴好,ES6 语法更佳,可以在这里跟阮老师学习,免费的电子书。文档和持续进阶不是你在两个框架间做选择的原因。

Vue 的话需要记住各种指令,还有属性细节,免不了经常查文档。React 相对简单,记住:“函数入口是 props,出口是 html”就行了。

为什么我们放弃了 Vue?Vue 和 React 深度对比_第2张图片

React 学习门槛高?

这个也不是你选择框架的原因,如果这个也可以作为原因的话,我觉得是因为你懒,给自己找了借口。据我自己学习、实践总结,两个框架都很简单,有手就行,有脑就会,不见得会 React 就比 Vue 牛逼很多。两者都提供了相应脚手架,方便用户使用:

Vue

npm install -g @vue/cli
vue create my-project

React

npx create-react-app my-app
cd my-app
npm start

傻瓜式使用,无限 div 就完事了。

为什么我们放弃了 Vue?Vue 和 React 深度对比_第3张图片

大项目用 React,小项目用 Vue

这是我以前在华为的时候,内部讨论两个框架对比时下的一个结论。
怎么说呢?这个就是万精油结论,没有参考意义。你如何定义一个项目是大项目?超过 xx 万行代码?后端 API 超过 xxx 个?无论什么项目,都有做“大”的可能,只要正常运营,你就得持续维护,补充新增的需求。框架的可持续演进更为重要。
当然我可以这么跟你说,React 适不适合“小”项目我不知道,但是 Vue 不适合“大”项目,业务代码超过 5 万行之后问题明显,后面会详细说这点。

XX 大公司也在用 Vue,我们跟随就行了

很多新手在入门一些框架,或者选型组件、方案时会看看哪些大公司已经用了,避免自己踩坑。当然啦,我也这么做滴。但是大公司可能只是“尝鲜”、“实验性”使用,这些项目对他们来说无关紧要,选型失败了,压力给到开发工程师,996 重构就行了,而你,╮(╯▽╰)╭ 项目和屎一样也得维护下去。

为什么我们放弃了 Vue?Vue 和 React 深度对比_第4张图片

举个选型错误的例子,看看大公司怎么拯救的。

以前在华为做硬件项目的时候,用的原理图软件,那叫一个辣鸡,用着用着总想砸掉电脑。历史问题,选型错误,但无奈很多项目、基础库都在上面,只能硬着头皮搞,迁移的成本太高,软件厂商水平太差,但是华为牛逼啊,把那个软件大改特改,各种内部数据库都集成在上面,各种自开发的辅助工具,还是可以开发出很牛逼的产品,部门做的单板连续11年全球第一。

如果你觉得你能搞定选型错误带来的问题,或者你在华为,那当我没说。(PS:以前还用 tcl 写脚本呢,你也可以试试蛋不蛋疼)

Vue 模板简单,React jsx 有学习成本

同上。两者都很简单,一学就会。连这点东东都叫学习成本,我只能说:“我不是针对你,我是说在座的各位都是......”
( Vue 的模板有很多工程实践问题,后面详说。)

为什么我们放弃了 Vue?Vue 和 React 深度对比_第5张图片

性能对比

可以看看这个第三方基准测试,两者都挺快的。不过我们实践过程中发现有差异,大列表渲染、大量数据加载,不做进一步优化的话 Vue 明显比 React 慢。TaskHub 这个网站我们以前就是用 Vue 写的,后来直接迁移到 React 前端性能大大提升,用户体验有明显差距(数据结构、后台不变)。

为什么我们放弃了 Vue?Vue 和 React 深度对比_第6张图片

深度对比

本来想简单写写,没想到前面写了那么多了,╮(╯▽╰)╭,下面是重头戏,写写实践过程中发现的问题,两个框架的解决思路。如果你还是小白,下面的一些东西可能没接触过,可以看下这篇文章:【译】通过创建相同的 APP,对比 React 和 Vue,亲自实现一下,了解基础知识。

市场占比

为什么我们放弃了 Vue?Vue 和 React 深度对比_第7张图片

相关 npm 下载量见上图,市场已经用脚投票了。看到这里,如果你只想知道选型结论,你可以走了。如果你还说 xx 大公司在用 Vue,跟着就行。可以这么说吧,大公司更多用的是 React,用 Vue 更多的目的是保留相关技术栈能力,多一个选择,避免 React license 事件再次发生。

当然,尤大也在这里说过,看npm下载量没用,实际使用应该参考 devTool 的下载量。但是...为啥我打开的很多网站下面这个标都是亮的?

开发生态

客观来说,作为核心团队成员,显然我们会更偏爱 Vue,认为对于某些问题来讲用 Vue 解决会更好。如果没有这点信念,我们也就不会整天为此忙活了。但是在此,我们想尽可能地公平和准确地来描述一切。其他的框架也有显著的优点,例如 React 庞大的生态系统

by Vue 官方

生态上的差距是明显的,这点 Vue 官方也承认的,很多人因为生态这点迁移到 React,不过我本人不是很在意,Vue 生态也不差,如果说你用了 React 生态的东西就觉得很牛逼,你的竞争对手也会用,这点并不能给你产品带来多大增值,竞争力还是要靠自己手码出来的好。下面简单带过:

UI 组件

两者的周边 UI 库都挺丰富的,React 稍微多一点,不过这不是选型的关键,自己手写 UI 库也不是什么难事,偶尔封装一下原生标签也是很简单的。以前用 Vue 的时候还没有太多 UI 库,手动写了一个功能比较全的 UI 库,用 rollup 打包,也就 2 万行代码左右,有手就行。

dom 相关的第三方库

Vue 和 React 都有 ref 可以操作 dom,自己封装一下不是什么难事。可以找找有没别人封装好的,拿来主义。

小程序(划重点)

有小程序开发经验的同学都知道,小程序原生开发是很蛋疼的,通常需要借助框架封装,代码转换。常见的有几个框架:

  • Taro (React 技术栈,推荐使用)
  • wepy(Vue 技术栈,强烈不推荐使用)
  • uni-app(Vue 技术栈,可以使用)

这些小程序开发框架都是基于 Vue 或者 React 的二次封装,简化小程序开发。

vue 的一些周边库和 Vue 强绑定,而不是以一个独立 js 库的形式存在。导致代码难以复用,相关 Bug、问题也带到了二次开发的框架中。

这种强依赖导致的问题会给以后项目升级、迁移带来很多问题。
比如 vuex 作为 Vue 官方推荐的状态管理方案,只能在 Vue 上面使用,不能在 React 上面使用。Redux 状态管理在 React 上用的多,这个却能用在 Vue 上面。
类似的问题很多,你会发现 React 周边的东西可以用于 Vue,Vue 的东西不能用在 React 上。

如果你觉得这个问题不严重,当你把 Vue 代码迁移到小程序 wepy 框架时发现,wepy 不支持 Vuex (bug 异常多),状态管理只能用 redux,欲哭无泪。
同样的问题,如果你用的是 React 相关技术栈,React 迁移到 Taro 小程序框架异常简单,而且还能一次性生成微信小程序、支付宝小程序、字节跳动小程序等,代码复用率高。

APP 生态

weex、rn 这块我没有比较好的实践经验,两者用于生产方案都要慎重考虑。rn 比 weex 成熟这点是明确的。

逻辑代码组织

为什么我们放弃了 Vue?Vue 和 React 深度对比_第8张图片

Vue 三种组件写法对比(Js 部分)

Object API 29 lines

import Vue, { PropOptions } from 'vue'

interface User {
  firstName: string
  lastName: number
}

export default Vue.extend({
  name: 'YourComponent',

  props: {
    user: {
      type: Object,
      required: true
    } as PropOptions
  },

  data () {
    return {
      message: 'This is a message'
    }
  },

  computed: {
    fullName (): string {
      return `${this.user.firstName} ${this.user.lastName}`
    }
  }
})

Class API 17 lines

import { Vue, Component, Prop } from 'vue-property-decorator'

interface User {
  firstName: string
  lastName: number
}

@Component
export default class YourComponent extends Vue {
  @Prop({ type: Object, required: true }) readonly user!: User

  message: string = 'This is a message'

  get fullName (): string {
    return `${this.user.firstName} ${this.user.lastName}`
  }
}

Function API 25 lines

import Vue from 'vue'
import { computed, value } from 'vue-function-api'

interface User {
  firstName: string
  lastName: number
}

interface YourProps {
  user?: User
}

export default Vue.extend({
  name: 'YourComponent',

  setup ({ user }: YourProps) {
    const fullName = computed(() => `${user.firstName} ${user.lastName}`)
    const message = value('This is a message')

    return {
      fullName,
      message
    }
  }
})
写法 优点 缺点
Object API Vue 官方写法,方便Vue直接处理组件 1. 代码长、缩进多,组件复杂时难以理清逻辑,不好进行分割
2. 混入较多Vue的概念,新手学习成本高
Class API 相关概念可以用class的思路理解,可以更好地描述Vue的混入、data、computed,生命周期钩子等概念。Vue 3.0 将原生支持class写法 用到了修饰器语法特性,目前还在实验阶段(typescript可以使用helper函数解决兼容问题,问题不大)
Function API 无状态(部分场景),更好的单元测试、并行化 函数式写法很容易写出回调地狱,导致代码可读性、可维护性差,目前纯粹function api 写法较少见

React 两种组件写法对比(Js 部分)

class 组件 34 lines

import React, { Component } from 'react';

interface P {}

interface S {}

class Index extends Component {

  constructor(props: Readonly

) { super(props); this.state = {}; } static defaultProps = {}; componentDidMount() {} componentDidUpdate(prevProps: Readonly

) {} componentWillUnmount() {} render() { return (

); } } export default Index;

函数组件 15 lines

import React, { FC } from "react";

interface Props {}

const Index: FC = (props) => {
  // js 代码

  return (
    
); }; Index.defaultProps = {}; export default Index;

在 js 逻辑部分两者写法没毛病,都需要用到框架特定的生命周期钩子,Vue 的 class 写法最为简洁(3种对比),React 的 function 写法最为清晰(全部写法对比)。这部分不是选择关键,怎么写是个人喜好。

组件内状态管理

Vue 使用的是数据对象(data),React 使用的是状态对象(不可变 state),这点两个框架的设计不同,如下的问题解决思路也不同。

  1. 我如何修改数据?

    • Vue 直接 this 引用数据对象,直接修改。
    • React 使用 setState 方法修改
  2. 框架如何发现数据被修改?

    • Vue 使用 es5 新方法 Object.defineProperty,劫持 setter、getter 实现数据监听。
    • React,你用了 setState,它通过这个函数就知道哪些数据变化了。
  3. 我如何发现数据被修改?

    • Vue:使用 watcher,或者 computed 属性发现
    • React:componentWillUpdate、componentDidUpdate 中可以监听变化,或者函数组件的依赖部分插入
  4. 框架何时渲染修改的数据,我如何知道已经渲染好了?

    • Vue:在适当的时候渲染,你通过使用 watcher,或者 computed 属性发现
    • React:setState 调用后在适当的时候重新渲染,并调用相关生命周期钩子

在组件状态管理功能上两者都没有太多槽点,如果要说的话就是 Vue watcher 写多了代码一堆缩进,比较难看,React 也没好多少。

Vue 的数据对象相比 React 的状态对象在代码膨胀的时候差距就来了。代码少的时候 Vue 的写法更为简洁,但组件状态很多,需要明确数据更新逻辑时,React 简单的 setState({}, callback),就搞定了,Vue 有点让人摸不到头脑。

Vue 项目解决 bug 和疑难杂症三大定理

  1. 没有什么是 deep watch 解决不了的,有就加 immediate
  2. 事件相关,dom 相关记得 nextTick
  3. 实在不行,就用 setTimeout

(来自某个师兄)

React 的不可变(immutable)状态在应用复杂时表现出的透明、可测试性更佳。

以上内容对比下来,感觉两者都OKOK的,功能也健全,Vue 生态差一点,但是可以自己动手丰衣足食。下面几点是我们真正弃用 Vue 的原因。

沃苏艾德布耀布耀德说过:同样的问题,在语言层面上的解决方案才是最佳解决方案。语言生命周期长于框架生命周期

模板语法 VS JSX

上下文丢失

Vue 的单文件组件,使用