Open mewcoder opened 6 months ago
Vue:
React:
1.API 方面:
2.性能方面:
速度
基于 Proxy 的响应式系统
编译优化:静态标记、静态提升等
diff 算法优化
体积:支持 tree-shaking
3.维护性:
TypeScript:更好的类型检查和类型推导,也省去了维护 d.ts 的麻烦
Monorepo:响应式库可以单独使用
函数式的优势 和 Options API 对比,分两个方面
还有就是函数式的优势
vue-class-component
提供的 Class API,依赖装饰器的提案不稳定Composition API Composition API 包括:
与 React Hooks 对比 灵感来源, 和 hooks 有相同级别的逻辑组织能力, React Hooks 组件更新时都会重新调用,有一些痛点:
避免子组件不必要的更新,要使用 useMemo / useCallback
而 Vue 是基于响应式系统的只执行一次,会自动收集依赖,可避免不必要的更新
vue 在组件初始化时,对对象的属性进行劫持,在 get 时进行依赖收集,set 时触发响应。
vue2:
对象使用Object.defineProperty
对属性进行劫持,嵌套对象是递归实现劫持的;
数组是通过重写数据的 7 个原型方法。
问题:
$set
/$delete
;Map
/Set
Vue3 使用 Proxy
对对象进行代理,拦截 set/get 行为
解决 Vue2 的问题,避免初始化时的性能开销,懒劫持
代理:拦截并重新定义对一个对象的基本操作
function reactive(target) {
const handler = {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
track(target, key); // 收集依赖
if (isObject(res)) return reactive(res); // 如果是对象,递归懒代理
return res;
},
set(target, key, value, receiver) {
const oldValue = target[key]; // 获取老的值
const result = Reflect.set(target, key, value, receiver);
if (!Object.is(oldValue, value)) {
trigger(target, key);
}
return result;
},
};
return new Proxy(target, handler);
}
// track: 收集依赖 存放targetMap: `WeakMap<object, Map<key, Set<effect>>`
为什么用 Reflect Reflect.xxx 提供对象的基本操作方法,与 proxy 拦截器 中的方法相对应,确保和对象默认行为一致 参数相同,传递参数,其中 receiver 能被正确的传递,确保调用时的 this 正确性
虚拟 DOM:
diff 算法:
最长递增子序列
进行增/删/移key 的作用
key 的作用是为了更高效的更新 DOM,diff 算法的目标就是尽可能复用原来对应的节点,减少 dom 操作量。
key 就是 vnode 的唯一 id,在 dom diff 的过程中,通过 key 找到对应原型的节点,来减少 dom 操作量,提升视图更新的性能。
Vue2 的过程是 parse -> optimize -> generate
optimize:优化原始 AST,标记静态节点。
Vue3 更加标准化,中间过程为 transform
vue3 的编译优化:编译阶段尽可能提取关键信息
patchFlag
对节点打上标记,为 runtime patch 提供依据,实现静态提升和靶向更新。dynamicChildren
收集子代所有的动态节点,无需层级遍历,做到靶向更新。
v-model
,可以绑定数据到视图,对应的视图变化也会改变该数据。v-model
是语法糖,默认情况下相当于:value
和@input
。v-model 经过模板编译被转换为属性 value
和一个事件监听,事件回调函数中会做相应变量更新操作。v-model
,也可以在自定义组件上使用v-model
只能去绑定一个变量,使用 .sync
可以实现多个变量的双向绑定v-model
有更新,类似.sync
,默认的 v-model
相当于:modelValue
和@update:modelValue
Vue 中的单向数据流是指数据的流向只能从父组件向子组件,子组件不能直接修改父组件中的数据,而是通过触发父组件中的事件来实现数据的修改
nextTick
,用户传入的回调函数被添加到刷新函数(flushSchedulerQueue
)的后面开发中缓存组件使⽤ keep-alive 组件,keep-alive 是 vue 内置组件,keep-alive 包裹动态组件 component
时,会缓存不活动的组件实例,⽽不是销毁它们,这样在组件切换过程中将状态保留在内存中,防⽌重复渲染。
结合属性 include 和 exclude 可以明确指定缓存哪些组件或排除缓存指定组件,集合 vue-router 缓存页面
activated 和 deactivated 钩子
keep-alive 是⼀个通⽤组件,它内部定义了⼀个 map,缓存创建过的组件实例,它返回的渲染函数内部会查找,如果该组件在 map 中存在就直接返回它。
指定了 max 后类似一个 LRU 缓存:如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。
一个 SPA 应用的路由需要解决的问题是页面跳转内容改变同时不刷新