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或hooks
DYNAMIC_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. vite
1. 基本原理是浏览器支持esm,不过需要高版本浏览器,chorme都要61以上,支持动态import要chorme63
1. 热更新和重新启动都非常快,并且热更新的速度不会随项目变大而变慢
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用模板渲染,更易于做静态分析,和一些渲染方面的优化。运行时的性能很高很快,延迟情况较少。
码字不易,点赞鼓励!!