Menu

React 和 Vue 的区别:并排代码对比

React 和 Vue 都是用组件构建用户界面的 JavaScript 工具。它们的区别在于标记写法(JSX 与模板)、响应变化的方式(不可变 state 加重新渲染,与可变的响应式 ref),以及生态中有多少是官方维护的。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

React 和 Vue 都是用组件构建用户界面的 JavaScript 工具(React 称自己为库,Vue 称自己为渐进式框架),它们的大多数理念是相同的:props 向下传递,事件向上发送,响应式 state,虚拟 DOM。实际的区别在于:React 用 JSX 编写标记,并要求通过 setter 替换 state;而 Vue 在单文件组件中用 HTML 模板编写标记,并允许你直接修改响应式值。下面是 React 中的计数器:

同一个计数器写成 Vue 单文件组件(Counter.vue):

<script setup>
import { ref } from 'vue';

const count = ref(0);
</script>

<template>
    <button @click="count++">Clicked {{ count }} times</button>
</template>

useState(0) 变成了 ref(0),onClick 变成了 @click,{count} 变成了 {{ count }}。最明显的区别是 count++:Vue 允许你直接修改值,它的响应式系统会察觉到。React 需要 setCount,因为只有当你交给它一个新值时它才会重新渲染。

JSX 与单文件组件

React 组件是一个返回 JSX 的 JavaScript 函数。条件用 && 或三元运算符,列表用 .map(),样式则由你自由选择(CSS 文件、CSS Modules、工具类框架)。

Vue 组件通常是一个包含三个部分的 .vue 文件:用于逻辑的 <script setup>、用于标记的 <template>,以及可选的 <style scoped>,其中的 CSS 只作用于该组件。模板使用指令:v-if、v-for、用于输入框双向绑定的 v-model、绑定值的 :prop 和监听事件的 @event。模板让懂 HTML 的人都能轻松读懂标记;JSX 则让你在标记中使用完整的 JavaScript。Vue 也能用 JSX,React 却不能用模板,但两边的大多数代码都遵循各自的默认写法。

下面是一个过滤列表,这是要对比的第二个功能。

试着输入 xyz,看看列表为空时的提示,然后删掉它。Vue 版本:

<script setup>
import { ref, computed } from 'vue';

const fruits = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Peach'];
const query = ref('');

const visible = computed(() =>
    fruits.filter((f) => f.toLowerCase().includes(query.value.toLowerCase()))
);
</script>

<template>
    <input v-model="query" placeholder="Filter fruit" />
    <ul>
        <li v-for="fruit in visible" :key="fruit">{{ fruit }}</li>
        <li v-if="visible.length === 0">No match</li>
    </ul>
</template>

v-model 取代了 value 加 onChange 的组合,computed 取代了普通变量。在 React 中,visible 每次渲染都会重新计算,因为组件函数会重新运行;在 Vue 中,computed 会缓存它,只在 query 变化时重新计算。两者都用 key 来区分列表项。

响应式模型

这是两者之间最根本的区别。

React:不可变 state 与重新渲染。state 是一个快照。你用新值调用 setter,React 再次运行组件函数,把新的 JSX 与旧的比较,然后更新 DOM。React 用 Object.is 比较值,所以原地修改一个对象或数组再把同一个对象传回去,看起来就像什么都没变。

点击“push() in place”,页面上什么都不会变,因为数组还是同一个对象。然后点击“New array”:渲染结果中也出现了 pushed,因为之前的修改确实发生了,只是 React 没有理由去查看。useState 页面深入讲解了这种模式。

Vue:可变的响应式值。ref 或 reactive 对象会记录谁读取了它(ref 通过它的 .value getter,reactive 对象通过 proxy)。当你写入它时,Vue 确切地知道哪些计算值、侦听器和模板部分依赖它,并且只更新这些部分。在 Vue 中,items.value.push('pushed') 就会更新页面。你需要写的样板代码更少,代价是失去了“值不会在你不知情时改变”的保证。

对于典型的应用来说,两种模型在速度上没有值得一提的差别。React 每次变化可能会运行更多的组件代码,并依靠记忆化(手写,或通过 React Compiler)来跳过不必要的工作;Vue 在运行时追踪依赖,所以默认就会跳过这些工作。

组合式 API 与 hooks

Vue 3 的组合式 API 和 React hooks 解决的是同一个问题:把相关的状态和逻辑放在一起,并在组件之间复用。Vue 把可复用的函数称为组合式函数(useMouse()),React 称之为自定义 hook(useMouse())。由于代码运行的时机不同,两者的规则也不同。

  • 何时运行。Vue 的 setup 在组件创建时运行一次。React 的组件函数每次渲染都会运行,其中的 hook 也随之运行。
  • 顺序规则。React 按调用顺序匹配 hook,所以不能在条件语句或循环中调用它们。Vue 的 ref 和 computed 没有这样的规则,因为 setup 只运行一次。
  • 依赖。React 的 effect 和 memo 要在一个由你维护的数组中列出依赖。Vue 的 watchEffect 和 computed 会自动追踪它们读取的值。
  • 过期的值。React 的回调可能捕获之前某次渲染中的旧 state 值(经典的 setInterval bug)。Vue 的回调在调用时读取 count.value,总能看到当前的值。

React 的模型让每次渲染都是 props 和 state 的纯函数,便于测试和推理。Vue 的模型消除了依赖数组相关的一类 bug。掌握其中一个的开发者,通常很快就能上手另一个。

生态

ReactVue
标记JSX.vue 文件中的 HTML 模板(JSX 可选)
state 更新用 setter 替换,然后重新渲染修改响应式值,依赖它的部分随之更新
逻辑复用自定义 hook组合式函数
派生值在渲染时计算,useMemocomputed(带缓存)
输入框双向绑定value 加 onChangev-model
作用域 CSS不内置(CSS Modules、第三方库)内置 <style scoped>
路由React Router、TanStack Router、框架Vue Router(官方)
全局状态context、Zustand、Redux ToolkitPinia(官方)
全栈框架Next.js、React Router 框架模式Nuxt
移动应用React Native无官方方案(Capacitor、NativeScript-Vue)
构建工具Vite 或框架Vite
维护者Meta 和社区独立的核心团队和社区

这张表体现出的规律是:Vue 的核心团队同时维护路由、store 和开发者工具,所以 Vue 项目在每一方面都有明确的默认选择。React 把这些交给社区,给了你更多选项,也带来更多需要做的决定。Vite 是两者新项目常用的构建工具,它正是由 Vue 的作者发起的。

学习曲线

Vue 的入门通常更平缓。模板读起来就像你已经熟悉的 HTML,v-model 省去了受控输入框的样板代码,修改响应式值页面就会更新。React 一开始就要求你掌握 JSX 和不可变更新的习惯,大多数人首先需要看的是 JSX 页面。

掌握基础之后,差距会缩小。Vue 有自己的概念要学(ref 与 reactive 对象、脚本中要写 .value 而模板中不用、侦听器),React 则有 effect、记忆化和 hook 的使用规则。比起语法,你所在地区的招聘需求更适合用来做最终决定。

该选哪个

选择 React,如果:

  • 你想要丰富的社区库和组件可选,或者打算用 React Native 开发原生移动应用。
  • 你喜欢把逻辑和标记放在同一个 JavaScript 函数中,并想使用 Next.js 这样的框架。
  • 你的团队看重明确、不可变的更新,让每次渲染都容易追踪。

选择 Vue,如果:

  • 你想要官方配套的路由和状态管理工具,少做一些决定。
  • 你的团队中有熟悉 HTML 模板的设计师或后端开发者。
  • 你要给现有的服务端渲染页面加上交互:Vue 可以通过一个 script 标签直接放进页面,再逐步扩展。

两者都很成熟,被各种规模的公司用于生产环境,你在其中一个里学到的概念(组件、props、派生状态、带 key 的列表)可以直接用到另一个上。

常见问题

Vue 比 React 简单吗?

很多初学者一开始觉得 Vue 更简单,因为模板看起来就像普通的 HTML,修改响应式值(count.value++)不需要 setter 就能更新页面。React 要求你学习 JSX,并遵守 state 必须被替换而不是被修改的规则。过了最初几周,两者的难度就差不多了。

React 和 Vue 哪个更好?

总体上没有哪个胜出。React 把路由和状态管理交给社区库,并且有用于移动端的 React Native。Vue 的官方路由、store 和开发者工具由同一团队一起维护,很多人也觉得它的模板更容易阅读。选择你的团队或当地就业市场在用的那个。

Vue 的组合式 API 和 React hooks 有什么区别?

两者都把有状态的逻辑组织成可复用的函数。Vue 的 setup 每个组件只运行一次,并自动追踪依赖,所以没有依赖数组,也没有过期闭包问题。React 的组件函数每次渲染都会运行,所以 hook 每次都必须以相同的顺序调用,effect 也要列出自己的依赖。

Vue 使用 JSX 吗?

Vue 可以通过插件支持 JSX,但大多数 Vue 代码在单文件组件(.vue 文件)中使用 HTML 模板。React 几乎处处都用 JSX。

Vue 中对应 Next.js 的是什么?

Nuxt。就像 Next.js 之于 React,它在 Vue 之上加入了基于文件的路由、服务端渲染、静态生成和服务器路由。

Coddy 编程语言插图

和 Coddy 一起学编程

开始