likes
comments
collection
share

Vue 与 React 全方位差异对比

作者站长头像
站长
· 阅读数 26

前言

作为国内前端最火的两个框架,Vue 和 React 一直被比较着。而作为一名成熟的前端当然是二者都要会!下面就梳理一下 Vue 和 React 这两个框架的差异性,只有做到心中有数,开发中进行切换才会做到游刃有余。而且面试中也不惧被提问:“既然你都使用过这两个框架,那么能说说它们之间的区别吗?”

基础对比

  • 关于组件:Vue 组件是一个 .vue 后缀文件,包含模板、样式和脚本代码,和 HTML 文件格式一样,很好理解;而 React 组件是一个 .jsx.tsx 后缀的文件,用的是其特有的 JSX 语法,模板和样式都可以写到 JS 里。
  • 关于插值:Vue template 中使用 {{}} ,React JSX 中使用 {}
  • 关于属性:Vue template 使用 v-bind:xxx动态绑定属性,或者简写为 :xxx ;而 React JSX 中,属性值如果是 JS 变量,依然用插值的语法 {xxx} 。
  • 关于状态和响应式: Vue3 提供了很多响应式 API 和工具,而 React 只有一个 useState Vue 与 React 全方位差异对比 Vue 是双向数据绑定,修改数据自动更新视图;而 React 单向数据流,需要手动 setState 触发视图更新。 - 注意,这里单向/双向数据流指的的是VM层,即是视图层数据层。而父子组件之间的数据流都是单向的,即不允许子组件直接修改父组件传递过来的数据。
  • 关于 Props:都可以通过 props 进行父子组件数据传递,只是 Vue props 要声明,React 不用声明可能直接使用。
  • 关于 DOM 事件:Vue 提供 v-on 指令,也可以简写为 @ 来监听 DOM 事件,用法:v-on:click="handler" 或 @click="handler"。React 必须使用驼峰写法,如 onClick={handler}
  • 关于自定义事件:在父子组件中传递调用自定义事件时,Vue 通过 @add="add" 添加绑定事件;React 中还是当属性传递,插值语法绑定事件 add={add}。但是 Vue 子组件需要通过 emit,React 子组件可以直接拿到 props 里的事件进行调用。
  • 关于样式:Vue 可以直接用 class,React 则需要使用 className,因为 React 完全是 JS 代码,class 是 JS 的关键字,没法直接使用。动态样式 Vue 有很多自己的写法,而 React 还是用插值语法。
  • 关于条件渲染:Vue template 使用 v-if 和 v-else 等指令实现判断逻辑条件渲染;React JSX 依然使用插值语法 {} ,只不过里面是使用 JS 表达式,如 { flag ? <Aaa/> : <Bbb/> }
  • 关于列表渲染:Vue template 中循环渲染使用 v-for 指令;而 React 还是使用 {xxx} 表达式。其中主要用到 JS 数组的 map 方法。
  • 关于生命周期:Vue 和 React 都定义了很多生命周期,这里主要举三个,组件挂载、更新、卸载生命周期:Vue 分别对应 onMounted()onUpdated()onUnmounted();React 组件只需要一个 useEffect hook 即可,挂载后执行 useEffect,在useEffect hook 里返回一个函数可以用于在组件卸载时触发调用,useEffect第二个参数是依赖项数组,可以处理更新的情况。
  • 关于 watch/computed:Vue 中 使用watch 监听某个数据,React 还是通过 useEffct 第二个参数(依赖项数组)实现。Vue 使用 computed 对计算结果进行缓存,React 中使用 useMemo 缓存结果。
  • 关于插槽:插槽,用于定义和显示子组件的内容。插槽的概念是 Vue 提出来的,什么具名插槽、作用域插槽···,其实插槽编译后就是一个普通对象;React 是通过 props 里的 children 拿到子组件。
  • 关于数据管理:Vue2 用 VueX,Vue3 用 Pinia;React 可选择的就更多,比如 Redux、dva、jotai、zustand等。
  • 关于 api:Vue API 概念更多,React API 少

响应式原理

  • Vue2 响应式的特点就是依赖收集,数据可变,自动派发更新,初始化时通过 Object.defineProperty 递归劫持 data 所有属性添加 getter/setter,触发 getter 的时候进行依赖收集,修改时触发 setter 自动派发更新找到引用组件重新渲染。
  • Vue3 响应式使用原生 Proxy 重构了响应式,一是 proxy 不存在 Vue2 响应式存在的缺陷,二是性能更好,不仅支持更多的数据结构,而且不再一开始递归劫持对象属性,而是代理第一层对象本身。运行时才递归,用到才代理,用 effect 副作用来代替 Vue2 里的 watcher,用一个依赖管理中心 trackMap 来统一管理依赖代替 Vue2 中的 Dep,这样也不需要维护特别多的依赖关系,性能上取得很大进步。
  • 相比 Vue 的自动化,React 则是基于状态,单向数据流,数据不可变,需要手动 setState 来更新,而且当数据改变时会以组件根为目录,默认全部重新渲染整个组件树,只能额外用 pureComponent/shouldComponentUpdate/useMemo/useCallback 等方法来进行控制。
  • Vue 通过数据劫持和代理来监测数据变化,能够精准地检测到具体数据的变化,触发相应的更新,因此更新粒度非常小。而 React 推崇函数式编程,这种方式无法感知数据变化,不知道何时应该刷新。即便是手动调用 setState 触发更新,它也无法确定哪些组件需要刷新,而是渲染整个虚拟DOM,基本上就是无差别刷新。这导致了性能问题,因此需要不断通过其他方法来避免不必要的刷新,或者优化这种无差别刷新的性能。

Diff 算法

  • Vue2 是同层比较新老 vnode,新的不存在老的存在就删除,新的存在老的不存在就创建,子节点采用双指针头对尾两端对比的方式,全量diff,然后移动节点时通过 splice 进行数组操作。
  • Vue3 是采用 Map 数据结构以及动静结合的方式,在编译阶段提前标记静态节点,Diff 过程中直接跳过有静态标记的节点,并且子节点对比会使用一个 source 数组来记录节点位置及最长递增子序列算法优化了对比流程,快速 Diff,需要处理的边际条件会更少。
  • React 是递归同层比较,标识差异点保存到 Diff 队列保存,得到 patch 树,再统一操作批量更新 DOM。Diff 总共就是移动、删除、增加三个操作,如果结构发生改变就直接卸载重新创建,如果没有则将节点在新集合中的位置和老集合中的 lastIndex 进行比较是否需要移动,如果遍历过程中发现新集合没有,但老集合有就删除。

总结

React JSX 语法非常简洁,只要记住下面两条就够了:

  • {xxx} 大括号里面是 JS 的变量或者表达式,可实现一切动态的功能,包括判断和循环
  • onXxx 是 DOM 事件的写法

而 Vue template 定义了更多的规则,例如:

  • :xxx 动态属性
  • @xxx 事件
  • :class:style 的多种写法
  • v-if v-for 等多种指令
  • 还有更多,如 v-model slot 等...

Vue 在更新时性能优化方面需要的心智负担会少一点,特别是 Vue3,而 React 如果不注意,容易导致一些组件无用的 Diff,但实际项目中真正能遇到这种性能瓶颈的也是极少数。

转载自:https://juejin.cn/post/7395147410212765705
评论
请登录