Vue和React的区别:从组件化开发到设计理念的全面解析
Vue和React的区别:从组件化开发到设计理念的全面解析
Vue和React是目前最流行的两个前端框架,它们在组件化开发、响应式数据绑定等方面有很多相似之处,但也有各自独特的特点。本文将从多个维度详细对比这两个框架的异同,帮助读者更好地理解它们的核心特性。
相同点
1. 组件化开发
Vue3 和 React 都采用了组件化开发的方式,使代码具有更好的可维护性和重用性。在 Vue3 中,组件可以被定义为一个对象,并且包含一个template、script 和 style 标签。在 React 中,组件可以被定义为一个类或者函数,并且采用 JSX 语法来描述组件的结构和行为。
2. 响应式数据绑定
Vue3 和 React 都支持响应式数据绑定,这意味着当数据变化时,UI界面会自动更新。在 Vue3 中,数据变化会触发视图的重新渲染,而在 React 中,则会调用组件的 render 方法重新生成虚拟DOM 树。
3. 虚拟DOM机制
Vue3 和 React 都采用了虚拟DOM 机制来进行高效的页面更新。虚拟 DOM 描述了UI 界面的状态和结构,当数据发生变化时,框架会通过比较前后两个虚拟DOM 树的差异来进行页面更新。
补充:VirtualDOM 的新旧对比
当发生改变时,通常会生成一个新的VirtualDOM结构来表示改变后的状态,然后进行“新旧”比较,找出差异性,得到一个差异树对象。
这里面有一个关键的地方,就是如何进行“新旧”比较。这里用到的算法实际上是对多叉树结构的遍历算法。而该遍历算法又分为深度与广度遍历。这里我们主要以深度优先遍历算法来讲解“新旧”比较的过程。(广度优先类似)
我们先看上图,对上图进行深度优先遍历的结果:abdecfg
接着改变一下,新增一块内容,如下图红色部分:
此时,对该图进行深度优先遍历的结果:ahijbdecfg
我们把这两个图的深度优先遍历结果放在一起,如下:
现在,我们是不是能容易地分析出需要再a和b节点之间插入hij节点。然后根据hij节点的关系,可以看出节点h是i与j节点的父节点,那么我们就知道了现在只需要插入完整的h节点。
4. 组件之间的通信
Vue3 和 React 都支持父子组件之间的通信。在Vue3 中,通过props 和 $emit 方法可以实现父子组件之间的数据传递和事件监听;React 通过props 和回调函数来实现同样的功能。
不同点
1. 响应式数据绑定的实现方式不同
Vue 3 使用了 Proxy API 来实现响应式数据绑定,并且能够动态添加和删除属性。而 React 需要使用 useState 方法来触发视图的重新渲染,这使得代码相对复杂一些。Vue 3 的响应式 API 还允许开发者在模版中直接使用 响应式数据,而React 需要手动将数据传递给组件。
2. 组件状态管理的实现方式不同
Vue 3 引入了 Composition API ,使得组件状态管理更加灵活和可维护。开发者可以将逻辑相关的代码封装为单独的函数,从而实现更高的代码复用和组织。
3. 组件渲染方式不同
Vue3 采用template 语法来描述组件的结构和行为,这使得代码可读性更高,并且能够更好地与设计师协作。在模版中可以使用if、for等语句来实现复杂的逻辑控制。React 通过 JSX 语法来描述组件的结构和行为,这使得代码更加灵活,更好地与 JavaScript 集成。但是,由于JSX 需要手动添加标签,因此代码的可读性相对较差。
4. API 设计风格不同
Vue3 的API 设计师倾向于提供语法糖和便捷方法,使开发更加高效。比如,Vue3 中提供了v-model 指令来实现双向绑定,在处理表单等情况非常方便。React 倾向于提供一些基础API,鼓励开发者自行封装复杂功能。代码更加灵活和可拓展,但需要花费更多的时间和精力。
设计理念&组件存在的形式&diff优化
设计理念
我们先来看一张React官网的截图:
从这张图中我们可以提取出两个主要信息:
- React组件就是函数
- 编写组件的语法是JSX,本质就是Javascript
我们平时写React实际就是在写JS,这也就是为什么React那么灵活的原因。灵活带来的优势就是上限高,劣势就是上手难度相对Vue较难。
所以在React社区中有高阶组件、compose函数、纯函数等概念,但是这些概念在Vue社区中很少提及。
而Vue从出生开始就一直在尽可能的降低前端开发门槛,通过什么方式降低呢?
Vue内置了很多黑魔法,比如:
- SFC
- 宏函数
- 指令
- scoped
等,其中最大的黑魔法就是单文件组件SFC。只要我们按照Vue的设计规范来,就能轻松的写出漂亮的代码。
同时Vue的设计也不会让人反感,因为学习他的这一套东西真的很容易,这也就是为什么很多后端同学写前端都是从Vue开始。
组件存在的形式
从前面的官网截图可以看到React中定义一个组件就是在定义一个函数,一个文件里面可以定义多个函数,所以理所应当的在一个文件中可以定义多个组件。
但是在Vue中事情就不一样了。大家都知道在Vue中一个.vue文件就是一个Vue组件,所以想正常的在一个.vue文件中定义多个Vue组件是不可能的。
大家知道一个Vue组件到底是什么样的吗?比如这个子组件count-child.vue:
<template>
<h1>count的值是: {{ count }}</h1>
<button @click="count++">count++</button>
</template>
<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
</script>
很简单!我们直接在父组件里面把他打印出来就知道这个组件到底是什么玩意了,父组件代码如下:
<script setup lang="ts">
import CountChild from "./count-child.vue";
console.log(CountChild);
</script>
我们来控制台上面看看打印出来的CountChild长什么样,如下图:
从上图中可以看到import导入进来的CountChild变量是一个对象,并且对象上面还有一些属性的方法:
- render
- setup
在父组件里面import CountChild from "./count-child.vue",这是使用了import语法,讲道理子组件里面应该是有export的,但是在子组件里面没有看到任何export的代码。
其实这些都是vue-loader或者@vitejs/plugin-vue做的工作,底层还是调用Vue暴露出来的编译API。
经过他们的处理一个.vue文件就变成了一个组件对象。
所以在Vue中组件其实就是对象,只是这个对象中拥有render、setup等方法。其实我们可以自己手写一个对象,按照Vue他的规则去定义对象里面的render、setup等方法同样可以定义一个Vue组件。
正是因为在Vue中组件就是对象,所以在Vue社区中才很少出现高阶组件、compose函数、纯函数等概念。因为这些东西都是依赖于函数去实现的,而React中组件就是函数。
diff优化
众所周知每重新渲染一次都会执行一次diff算法,如果参与diff的DOM足够复杂,那么这个diff的过程也是很耗时的。
在优化diff上面Vue和React走向了两个极端,Vue走向了更加细粒度的更新,也就是大名鼎鼎的靶向更新,如果你不知道可以看一下这篇 靶向更新 文章。而React则是引入了fiber,采用时间切片的方式进行优化。
那么为什么React中没有实现靶向更新呢?
原因很简单,因为Vue的template模版很不灵活,也正是因为不灵活所以可以在编译时就对代码进行分析出哪些节点是动态的。相反在React中的JSX是相当灵活,想对他进行静态分析很难实现。