涉及到了,就顺便中间插一篇选型的文章
一、为什么重写vue2?
1、作者角度出发
- 主流浏览器对新的JavaScript语言特性的普遍支持。
- 当前
Vue代码库随着时间的推移而暴露出来的设计和体系架构问题。
2、自己使用感受出发
- ts终究会是前端的主流,vue3对于ts的支持更加友好
- Composition API对于组件的封装尤其是无状态组件的封装更加友好,而且能够释放程序员的写法,不再是固定的框架
- 响应式功能更加的强大和彻底
二、vue2和vue3的全面对比
2.1 生命周期的变化
| Vue2.x | Vue3 |
|---|---|
| beforeCreate | 使用 setup() |
| created | 使用 setup() |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeDestroy | onBeforeUnmount |
| destroyed | onUnmounted |
| errorCaptured | onErrorCaptured |
生命周期上没有特别大的改动,只是在写法上可能有些小改动,总体基本持平吧,对于习惯了vue2的人可以进行平稳过渡
2.2 使用proxy代替defineProperty(核心)
这个改动算是vue2到vue3的一个核心改动点儿:
为什么?
在vue3.0之前vue一直是使用的Object.defineProperty进行的拦截实现的双向数据绑定,vue2.x的双向绑定的核心:收集依赖、配置watcher监控、更新改变后去通知视图更新
但是有个问题,就是手动新增属性和值后或者直接通过数组索引去修改数组项,视图并不会去更新:原因就是, 1、data init是在生命周期created之前进行的操作,会对data绑定一个观察者observer,之后data中的字段更新都会通知依赖收集器Dep触发视图更新,但是在Observer data的时候,新增的属性并不存在,自然就不会有setter,getter了,所以就不会更新,当然vue也提供了方法$set()自己手动去给新增的属性observer
对比之下,Proxy优势:能观察的类型比defineProperty更丰富;Object.defineProperty是劫持对象的属性,新增元素需要再次Definepeoperty,但是Proxy劫持的是整个对象,不需要做特殊处理
使用definepeoperty时,我们修改原来的obj对象就可以触发拦截,但是Proxy必须修改代理对象,即Proxy的实例才可以触发拦截。
还有一个点儿就是:vue2.x只能兼容到IE8时因为defineProperty无法兼容IE8;proxy的话直接放弃了IE,所以对IE包括IE内核的浏览器都不支持。
2.3 性能提升(核心)——diff算法优化
之前的vue2.x,就是将模版编译成渲染函数来返回虚拟DOM。vue框架通过递归遍历两个虚拟DOM树,比较其中的差异来确定哪些部分需要更新。vue2的diff的优化策略就是在比较的过程中前后节点的双端对比以及冻结节点来加快性能。
vue2的DOM树的对比其实是一个全量对比,每个节点都会彼此比较,不管这个节点有没有发生变化,如果是复杂的大型项目,必然存在很复杂的父子关系的vNode,vue2.x的diff算法会不断递归调用pathVNode,不断堆叠而成的几毫秒,最终就造成了vNode更新缓慢。
vue3在原先的基础上进一步的进行了优化:动静结合 PatchFlag
vue3在模版编译的过程中,就会在动态标签的末尾加上/Text/PathFlag。也就是在生成VNode的时候就同时打上了标记,在这个基础上在进行核心的diff算法并且PatchFlag会标识动态的属性类型有哪些,比如这里的TEXT表示只有节点中的文字时动态的,引用一张图:
其中大致可以分为两类:
- 当 patchFlag 的值「大于」 0 时,代表所对应的元素在 patchVNode 时或 render 时是可以被优化生成或更新的。
- 当 patchFlag 的值「小于」 0 时,代表所对应的元素在 patchVNode 时,是需要被 full diff,即进行递归遍历 VNode tree 的比较更新过程。
总结就是:vue3对于不参与更新的元素,做静态标记并提示,只会被创建一次,在渲染时直接服用。
其次还有一个就是事件侦听器缓存 cacheHandlers
默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化,但是因为是同一个函数,所以没必要去追踪它的变化,想办法将它直接缓存起来复用就会提升性能。
onClick会被视为动态绑定,但是它有静态标记,8是动态属性。开启cacheHandlers后,静态标记就不存在了,那么这部分内容也就不会进行比较了。
整体性能至少提升5倍以上吧
2.4 TS的支持
ts对于前端的前景和火爆程度,每个前端应该都能感受得到吧,ts肯定会成为一个前端的主流,所以框架对于ts支持的友好程度也是一部分的选型原因。vue2之前大家应该大多都是在用着插件去对vue2的ts进行一个支持和优化,但vue3开始包括vue3的语法和函数、方式等等,明显在向着这个方面前进。
2.5 打包体积的变化
之前的vue2的打包机制,随着代码和依赖等的变多,在打包的工程中总会将一些无用的代码打包进去,造成了打包体积变大。
vue3的话加入了Tree shaking(即摇树),可以将无用的代码不再进行引入和打包,大大减少了打包的体积
2.6 其他的优化改动
Composition API:
如果你想自由的编程,那么你一定要试试,具体就不在这儿细说了,感兴趣可以翻看我其他文章。
Fragment(碎片):
你不用再必须用一个template标签包起整个组件,一个文本一个标签,多个template都可以。
Teleport(传送门):
Teleport 是一种能够将我们的模板移动到 DOM 中 Vue app 之外的其他位置的技术,常用的就是像toast,modals这样元素使用,意味着我们可以使用,在vue应用的范围之外去渲染他
Custom Renderer API(比较少用):
意味着以后可以通过 vue, Dom 编程的方式来进行 webgl 编程
Suspense:
可在嵌套层级中等待嵌套的异步依赖项;支持async setup();支持异步组件
vue-cli 从 v4.5.0开始提供 Vue 3 预设
Vue Router 4.0 提供了 Vue 3 支持,并有许多突破性的变化
Vuex 4.0 提供了 Vue 3 支持,其 API 与 2.x 基本相同
并且vue3还有着配套的例如vite,pinia等工具
三、Vue3 Hook与 React Hook 的对比
Hook 和 Mixin & HOC 对比
说到这里,还是不得不把官方对于「Mixin & HOC 模式」所带来的缺点整理一下。
- 渲染上下文中公开的属性的来源不清楚。 例如,当使用多个 mixin 读取组件的模板时,可能很难确定从哪个 mixin 注入了特定的属性。
- 命名空间冲突。 Mixins 可能会在属性和方法名称上发生冲突,而 HOC 可能会在预期的 prop 名称上发生冲突。
- 性能问题,HOC 和无渲染组件需要额外的有状态组件实例,这会降低性能。
而 「Hook」模式带来的好处则是:
- 暴露给模板的属性具有明确的来源,因为它们是从 Hook 函数返回的值。
- Hook 函数返回的值可以任意命名,因此不会发生名称空间冲突。
- 没有创建仅用于逻辑重用的不必要的组件实例。
当然,这种模式也存在一些缺点,比如 ref 带来的心智负担
React Hook 和 Vue Hook 对比
其实 React Hook 的限制非常多,比如官方文档中就专门有一个**章节**介绍它的限制:
- 不要在循环,条件或嵌套函数中调用 Hook
- 确保总是在你的 React 函数的最顶层调用他们。
- 遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。
而 Vue 带来的不同在于:
- 与 React Hooks 相同级别的逻辑组合功能,但有一些重要的区别。 与 React Hook 不同,
setup函数仅被调用一次,这在性能上比较占优。 - 对调用顺序没什么要求,每次渲染中不会反复调用 Hook 函数,产生的的 GC 压力较小。
- 不必考虑几乎总是需要 useCallback 的问题,以防止传递
函数prop给子组件的引用变化,导致无必要的重新渲染。 - React Hook 有臭名昭著的闭包陷阱问题(甚至成了一道热门面试题,omg),如果用户忘记传递正确的依赖项数组,useEffect 和 useMemo 可能会捕获过时的变量,这不受此问题的影响。 Vue 的自动依赖关系跟踪确保观察者和计算值始终正确无误。
- 不得不提一句,React Hook 里的「依赖」是需要你去手动声明的,而且官方提供了一个 eslint 插件,这个插件虽然大部分时候挺有用的,但是有时候也特别烦人,需要你手动加一行丑陋的注释去关闭它。
- React Hook 的心智负担是真的很严重
总结来说就是:React上限会比较高,但是取决于你自己的思考和编码的上线,当你遇到很复杂的一个项目,你去造每个hook都会变得异常困难,而且会有你考虑不周的地方可能就会整个项目连锁反应报错;
推荐看下这篇文章:使用 react hooks 带来的收益抵得过使用它的成本吗? - 李元秋的回答 - 知乎www.zhihu.com/question/35…
但是vue的话想对会比react容易理解和使用,当然都能实现功能,但是后期可能会想对没有那么清晰和比较臃肿