大前端百科全书,前端界的百科全书,记录前端各相关领域知识点,方便后续查阅及面试准备
- 说一下对vue3.0的了解,vue3.0为什么要用代理?
- 说一下 Vue3 的 Composition API
- vue Hooks 有哪些?
说一下对vue3.0的了解,vue3.0为什么要用代理?
vue3重写了多种机制
主要是基于:
- 主流浏览器对新的JavaScript语言特性的普遍支持
- 当前vue代码库随着时间的推移而暴露出来的设计和体系架构问题
vue3较vue2做了很多优化
- 1.
重写VDOM机制:通过编译时的标记优化运行时的速度 - 2.
优化插槽(slot)生成:原来的实现是父组件重渲染时子组件必须同时渲染,而在vue3中子组件提取函数,可以分别渲染。 - 3.
静态树提升:没有响应式绑定的部分被提取出来作为常量,用到的时候不用再次执行它的渲染函数 - 4.
静态属性提升:没有响应式绑定的组件属性(props)被提取出来作为常量,用到的时候不用再自行创建。 - 5.
项目结构优化:内部解耦、更好维护,支持了细粒度的tree-shaking,比如可选的生命周期
Object.defineProperty与Proxy
在vue2中,Object.defineProperty会改变原始数据,而Proxy是创建对象的虚拟表示,并提供set、get和deleteProperty等处理器,这些处理器可在访问或修改原始对象上的属性时进行拦截,有以下特点:
- 不需要使用 Vue.delete 触发响应式
- 全方位的数组变化检测,消除了vue2无效的边界情况
- 支持Map、Set、WeakMap和WeakSet。
Proxy 实现的响应式原理与vue2的实现原理相同,实现方式大同小异:
-
1、get收集依赖
-
2、set、delete等触发依赖
-
3、对于集合类型,就是对集合对象的方法做一层包装:原方法执行后执行依赖相关的收集或触发逻辑
说一下 Vue3 的 Composition API
首先要了解一下 Composition API 设计的好处在哪里? 逻辑组合和复用、类型推导、打包尺寸等
在 vue3.0 之前所有的组件都可以看作一个可选项的配置集合,通过 data、computed、methods、watch、以及 created、mounted 等声明周期函数,用这个可选项集合来声明一个组件。
这样写的好处是组织结构清晰,但是在逻辑复用上就不太友好啦,我们都知道的是 js 中最简洁清晰的复用方式就是将逻辑封装到一个函数中,然后函数与函数之间相互调用。
Vue3.0 很好的支持 TS,而 TS 的最重要的一个特性就是类型推导,而函数相对于嵌套的对象来说对类型推导更加友好
另外,以函数形式组织的模块以具名方式导入使用,在tree-sharking的时候支持会更好
vue Hooks 有哪些?
什么是 Hooks
hooks 字面意思就是钩子函数,那么钩子函数的定义是什么呢?
钩子函数:在一个事件触发的时候,在系统级捕获到了它,然后做一些操作。一段用以处理系统消息的程序。
钩子就是在某个阶段给你一个做某些处理操作的机会-----类似回调函数
钩子函数:
一个函数/方法,在系统消息触发时被系统调用,例如click等事件调用
不是用户自己触发的,例如发布订阅者模式的方法的实现
钩子函数的名称时确定的,当系统消息触发后,自动会调用
例如Vue的watch()函数,用户只需要编写watch()的函数体里面的函数,当页面元素发生变化的时候,系统就会先调用watch()
例如react的componentWillUpdate函数,用户只需要编写componentWillUpdate的函数体,当组件状态发生改变更新的时候,系统就会调用componentWillComponent
Vue Hooks 就是一些 vue 提供的内置函数,这些函数可以让 Function Component 和 Class Component 一样能够拥有组件状态(state)以及进行副作用(side effect)
为什么使用 Vue Hooks?
首先从 Class-component/Vue-options 开始说起
- 跨组件代码难以复用
- 大组件,维护困难,颗粒度不好控制,细粒度划分时,组件嵌套层次太深会影响性能
- 类组件,this 不可控,逻辑分散,不容易理解
- mixins 具有副作用,逻辑互相嵌套,数据来源不明,且不能互相消费
当一个模板依赖很多 mixin 的时候,很容易出现数据来源不清或者命名冲突的问题,而且开发 mixins 的时候,逻辑以及逻辑依赖的属性互相分散且 mixins 之间不可互相消费。这些都是开发中令人痛苦的点,因此 vue3.0 中引入 hooks 相关的特性非常明智
常用的 hooks 讲解
1、withHooks
const Foo = withHooks((h) => {
// state
const [count, setCount] = useState(0);
// effect
useEffect(() => {
document.title = "count is " + count;
});
return h("div", [
h("span", `count is: ${count}`),
h(
"button",
{
on: {
click: () => setCount(count + 1),
},
},
"+"
),
]);
});
withHooks 是一个高阶函数,传入一个函数,这个函数内部返回一个 vnode,withHooks 方法返回的是一个 vue 的选项对象
Foo = {
created() {},
data() {},
render() {},
};
这个选项对象可以直接调用 Vue.component 方法生成全局组件,或者在 render 方法中生成 vnode
2、useState
useState 理解起来很简单,和 Class Component 的 vuex 中 state 是一样的,都是用来管理组件状态的。因为 Function Component 每次执行的时候都会生成新的函数作用域所以统一组件的不同渲染(render)之间是不能够共用状态的,因此开发者一旦需要在组件中引入状态就需要将原来的 Funtion Component 改为 Class Component,这使得开发者的体验十分不好。useState 就是用来解决这个问题的,它允许 Function Component 将自己的状态持久化到 vue 运行时的某个地方,这样在组件每次渲染的时候都可以从这个地方拿到该状态,而且当该状态被更新的时候,组件也会重渲染
//声明
const [count, setcount] = useState(0)
const [state, setState] = useState({
status: 'pending',
data: null,
error: null
})
const handleTextChange(value) => {
setText({
status: 'changed',
data: value,
error: null
})
}
//引用
<div>{count}</div>
< ... onClick= setcount(count + 1) ... >
<div>{state}</div>
onChange=handleTextChange(count)
useState 接收一个 initial 变量作为状态的初始值,返回值是一个数组。
返回数组的第一个元素代表当前 state 的最新值,第二个元素是一个用来更新 state 的函数。这里要注意的是 state 和 setState 这两个变量的命名不是固定的,应该根据你业务的实际情况选择不同的名字,可以是 setA 或 setB,需要注意的是 setState 这个是全量替代
我们在实际开发中,一个组件可能不止一个 state,如果组件有多个 state,则在组件内部多次调用 useState,这些使用类似 Vuex 里面的 state 的使用方式
3、useEffect
useEffect 用于添加组件状态更新后,需要执行的副作用逻辑
useEffect 指定的副作用逻辑,会在组件挂载后执行一次、在每次组件渲染后根据指定的依赖有选择地执行、并在组件卸载时执行清理事件的逻辑
import { withHooks, useState, useEffect } from "vue-hooks";
const Foo = withHooks((h) => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = "count is " + count;
});
return h("div", [
h("span", `count is: ${count}`),
h("button", { on: { click: () => setCount(count + 1) } }, "+"),
]);
});
代码中,通过 useEffect 时,每当 count 的状态值发生变化时,都会重置 document.title。这里没有指定 useEffect 的第二个参数 deps,表示只要组件重新渲染都会执行 useEffect 指定的逻辑,不限制必须是 count 变化时
4、useRef
useRef 是用来在组件不同渲染之间共用的一些数据的,它的作用和我们在 Vue Class Component 里面为$refs.xxx 赋值是一样的。那么它的一些特性就跟 refs 是类似:
- 组件更新之后,可以获取最新的状态、值
- 值不需要响应式处理
- 独立于其他作用域之外,不污染其他作用域
- useRef 返回的是对象
const [count, setcount] = useState(0);
const num = useRef(count);
const addCount = () => {
let sum = count++;
setcount(sum);
num.current = sum;
console.log(count, num.current);
};
//得到的结果是
// 0 1
// 1 2
// 2 3
// ...
5、useData
useData 可以理解为 Vue Class Funtion 里面的$data,也可以认为与 useState 类似。不同的是:useState 不提供更新器。只是作为数据变量的声明、修改、调用
// 声明
const data = useData({
count: 0,
});
// 调用
console.log(data.count);
6、useMounted
useMounted 需要在 mounted 事件中执行的逻辑
useMounted(() => {
console.log("mounted!");
});
7、useDestroyed
useDestroyed 需要在 destroyed 事件中执行的逻辑
useDestroyed(() => {
console.log("destroyed!");
});