Vue2 vs Vue3 vs React vs Hook(类编程vs函数式编程 )
一些日常业务中,对vue2 vue3 react hook等的理解总结。分为3块对比
- Vue2 vs Vue3
- 类编程 vs 函数式编程 (vue2 -> vue3 / class -> hook)
- React vs Vue
Vue2 vs Vue3
- vue3是monorepo架构,更好按需加载,使得核心库变得更小(加载 执行都变快)
- vue3更快的update的速度
- 缓存 模板上元素绑定的事件
```jsx
- 缓存 模板上元素绑定的事件
```jsx
import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from “vue”
export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock(“div”, { id: “app” }, [ _createElementVNode(“button”, { onClick: _cache[0] || (_cache[0] = (…args) => (_ctx.handleClick && _ctx.handleClick(…args))) }, “戳我”), _createElementVNode(“button”, { onClick: _cache[1] || (_cache[1] = () => { _ctx.console.log(111) }) }, “戳我”) ])) }
2. **增加对静态节点的标记,相当于缓存静态节点**```jsx<div id="app"><h1>我是静态节点</h1><div>{{name}}</div><div :class="{red:isRed}">摸鱼符</div><button @click="handleClick">戳我</button><input type="text" v-model="name"></div>// 打包后import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"export function render(_ctx, _cache) {return (_openBlock(), _createBlock("div", { id: "app" }, [_createVNode("h1", null, "我是静态节点"),_createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */),_createVNode("div", {class: {red:_ctx.isRed}}, "动态节点", 2 /* CLASS */),_createVNode("button", { onClick: _ctx.handleClick }, "戳我", 8 /* PROPS */, ["onClick"])]))}// 动态节点注释表TEXT = 1,// 表示具有动态textContent的元素CLASS = 1 << 1, // 表示有动态Class的元素STYLE = 1 << 2, // 表示动态样式(静态如style="color: red",也会提升至动态)PROPS = 1 << 3, // 表示具有非类/样式动态道具的元素。FULL_PROPS = 1 << 4, // 表示带有动态键的道具的元素,与上面三种相斥HYDRATE_EVENTS = 1 << 5, // 表示带有事件监听器的元素STABLE_FRAGMENT = 1 << 6, // 表示其子顺序不变的片段(没懂)。KEYED_FRAGMENT = 1 << 7, // 表示带有键控或部分键控子元素的片段。UNKEYED_FRAGMENT = 1 << 8, // 表示带有无key绑定的片段NEED_PATCH = 1 << 9, // 表示只需要非属性补丁的元素,例如ref或hooksDYNAMIC_SLOTS = 1 << 10, // 表示具有动态插槽的元素
- 类编程 到 函数式编程 (vue2 到 vue3)
- 组合式api:大型应用中,逻辑可以组合在一起,会更清晰好维护
- 某些方面变得更加手动而不是自动。
- 在vue2中,每个组件都会被自动注入route和store,vue3变得可控
- 在组合式api内,可以像react一样,写多个hook组合,比如 ```jsx // 如果是vue2的话,数据只能放在data里,生命周期钩子只能有一个,多段无关逻辑 都耦合在钩子里
// 以下是vue3,组合式 const aa = ref(1) onMounted(() => { console.log(aa.value) }) watch(…)
const cc = ref(‘’) computed(…) onMounted(() => { console.log(‘处理cc的逻辑’) })
4. 更好typescript支持4. 响应式核心api 从 Object.definedProperty -> **Proxy** (**更加彻底的监听**)4. vite1. 基本原理是浏览器支持esm,不过需要高版本浏览器,chorme都要61以上,支持动态import要chorme631. 热更新和重新启动都非常快,并且热更新的速度不会随项目变大而变慢1. 第一次构建还是需要时间,之后就很快。第一次需要依赖预构建 用的esbuild(速度很快)<a name="9c19af3e"></a>## 类编程 vs 函数式编程| | 类编程 | 函数式编程 || --- | --- | --- || vue | vue2 | vue3(setup内) || react | class | 函数式 + hook |**函数式编程优点**:1. 代码逻辑更加清晰,**可以脱离class的 this/bind 编程**(这是js语言的特性,与react无关)1. 使用hook之后,**封装和复用都变得更加简单**,**结构清晰**1. 之前要用高阶组件的方式,层级深了后,会比较混乱(最明显的是redux支持hook后,使用起来简单多了)3. **组合式api(hook)**,让逻辑变得**更加的集中**,**不会分散**,使大型项目会更好维护1. **可以写多个 useState + useEffect 的组合**,**让逻辑更加集中**(vue也可以写多个 onMounted,watch)1. **之前的话,在大型复杂应用中:数据只能在state内,一个生命周期钩子内,会包含很多七零八落、互不相关的逻辑。例如**:```jsx// 用class,类编程class FriendStatusWithCounter extends React.Component {constructor(props) {super(props);this.state = { count: 0, isOnline: null }; // 互不相关的数据,也只能写在state里面,this.handleStatusChange = this.handleStatusChange.bind(this);}componentDidMount() { // 2段互不相关的逻辑,写在里面document.title = `You clicked ${this.state.count} times`;ChatAPI.subscribeToFriendStatus(this.props.friend.id,this.handleStatusChange);}componentDidUpdate() {document.title = `You clicked ${this.state.count} times`;}componentWillUnmount() {ChatAPI.unsubscribeFromFriendStatus(this.props.friend.id,this.handleStatusChange);}handleStatusChange(status) {this.setState({isOnline: status.isOnline});}}// ----------------------------------------// 用hook 函数式编程function FriendStatusWithCounter(props) {const [count, setCount] = useState(0);useEffect(() => {document.title = `You clicked ${count} times`;});const [isOnline, setIsOnline] = useState(null);useEffect(() => {function handleStatusChange(status) {setIsOnline(status.isOnline);}ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);return () => {ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);};});}
- 弱化生命周期概念,一个useEffect 就可以替代3个生命周期。vue3也去掉了2个钩子
- 这方面react做的比vue更彻底。不过,虽然编码更清晰,但可能也会让新手不好理解useEffect
React vs Vue
相同点:
- 都是spa单页面,性能、生态、编码体验都很不错,都是基于虚拟dom + diff算法更新页面。vue也可以写jsx。用vue写jsx的话,写法上基本和react就很像了,就是一些api的用法不一样
不同点 (6个方面):
- vue会多做一层模板编译(vue-loader, VueLoaderPlugin),这样带来的好处:
- 可以支持3段式的写法,对新手比较友好 ```html
```
- 很容易做css模块化,解决样式冲突问题
- 可以支持指令,具名插槽,比如 v-model v-if v-show v-for、v-on
- 更容易做静态分析,做性能优化。比如:缓存静态节点 和 节点事件
- vue更偏向于自动挡,react 手动挡
- pureComponent,React.memo
- react有pureComponent,React.memo 这种做渲染优化,当state或props的值没改变时,即使触发了setState也不触发render。
- 这个在vue里面就是自动的,相当于默认就加好了
- 但是 react可以通过 shouldComponentUpdate 控制某些情况不render,vue做不到
- 对于使用 router 和 redux的store 时
- vue都是自动高阶函数注入的(mixin),每个组件都可以直接通过this去获取。使用起来非常简单
- react则需要自己手动的用高阶函数的方式注入store,props的方式往下传递,使用起来很麻烦。不过,有hook之后,会简单很多
- 不过对于vue2来说,这是不可控的,无论你是否要用store或router,他们都被挂到了当前组件的实例上面。vue3支持手动控制
- setState触发render方面
- vue是响应式的,是自动的,直接改数据就能触发render。不用主动调用setState,也不用做对象的merge合并。
- vue3用了Proxy会更彻底的监听,vue2的监听 缺陷还是有一些
- react需要主动调setState,并且存在同步/异步的情况。
- 正常在react控制范围内,多次setState就是异步的 只会render一次(内部做了性能优化)。 但在react 控制范围之外,比如setTimeout,addEventListener的回调函数内,多次setState会render多次(有些损害性能)
- vue不会有这个问题,统一是异步的只render一次
- react多次setState 也不会拿不到上一次的值,需要传回调函数才能拿到上一次的值
- 状态管理方面
- vue是响应式的,是自动的,直接改数据就能触发render。不用主动调用setState,也不用做对象的merge合并。
- 较为接近
- vuex使用起来要更简单一点,vuex用mutation替代了redux的reducer里面的switch,并通过store.commit传入对于mutation的名字 可以直接触发类似react的 dispatch。
- vue还多了一个事件监听和发射emit,多了一种子传父的方式
- 封装组件方面
- 普通组件props组件比较接近
- slot方面差别较大
- vue有具名插槽,react是render props
- react原生支持jsx,vue需要配置才能支持jsx
- 如果vue开发者不熟悉jsx的话,jsx的封装能力 个人觉得 要比vue本身的形式 要强
- 因为,用jsx的话,逻辑可以按需 按函数的形式 拆成更多小快。
- vue的话,一个.vue文件内,一般是3段式,只会存在一个组件。需要别的组件要外引。react中一个.jsx文件内,可以存在N个组件
- vue如果写jsx的话,这方面就也差不多。但vue的开发者,写jsx的比较少
- 如果vue开发者不熟悉jsx的话,jsx的封装能力 个人觉得 要比vue本身的形式 要强
- 样式污染方面
- vue自带处理了css module的问题,react需要用create-react-app支持,或额外配置
- diff算法方面
- react是双指针,只支持前前遍历。比如 123 变成了 4123,那就扫不到,如果没设置key的话,会全部重新替换
- vue是4指针,除了前前遍历,还有前后,后前,后后遍历
- 都支持为元素加key,在进一步提升性能。(key值最好稳定一点,否则损耗性能)
- 因为dom树的层级结构一般情况下,都不会有大改变,并且标签类型很少会改变。所以:
- 如果标签的类型改变了(比如div变成span),那会直接创建一个新的标签+里面的内容,不会在往下遍历。 同类型标签,才会进一步去查找差异点
- 都是 只支持兄弟元素间的位置变动,不支持移动到其他位置。移到其他位子会重新渲染整颗子树
- Fiber方面
vue3为什么不使用 Time Slicing(Fiber)?
- 作者尢大大回答过,大致的意思是:vue很快,没必要做Fiber
- vue用模板渲染,更易于做静态分析,和一些渲染方面的优化。运行时的性能很高很快,延迟情况较少。
(没有时间切片-> 没有fiber-> 更少的开销)本质上更简单,因此虚拟DOM操作更快
通过分析模板进行了大量的AOT优化,减少了虚拟DOM操作的基本开销。Benchmark显示,对于一个典型的DOM代码块来说,动态与静态内容的比例大约是1:4,Vue3的原生执行速度甚至比Svelte更快,在CPU上花费的时间不到React的1/10。
(pureComponent,vue是自动的)智能组件树级优化通过响应式跟踪,将插槽编译成函数(避免子元素重复渲染)和自动缓存内联句柄(避免内联函数重复渲染)。除非必要,否则子组件永远不需要重新渲染。这一切不需要开发人员进行任何手动优化。
这意味着对于同一个更新,React应用可能造成多个组件重新渲染,但在Vue中大部分情况下只会导致一个组件重新渲染。 - 一般超过16ms的cpu任务,时间切片开始发挥作用。但是除非在进行动画,否则100ms内的掉帧用户一般无感知(并且动画可以用GPU硬件加速优化)
- 另外,如果是大量DOM更新操作,那么无论是否用了Fiber,都会有丢帧的感觉
- 并且使用Fiber架构本身会增加核心库体积和cpu计算
- vue用模板渲染,更易于做静态分析,和一些渲染方面的优化。运行时的性能很高很快,延迟情况较少。
码字不易,点赞鼓励!!
