defineComponent重载函数
它并没有实现任何的逻辑,只是把接收的 Object 直接返回
它的存在是完全让传入的整个对象获得对应的类型
它的存在就是完全为了服务 TypeScript 而存在的。
defineComponent函数,只是对setup函数进行封装,返回options的对象;
defineComponent最重要的是:在TypeScript下,给予了组件 正确的参数类型推断
setup
1、setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数
2、setup函数是 Composition API(组合API)的入口
3、在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用
Reactive
Vue 3的根基。返回对象的响应式副本,响应式转换是“深层”的——它影响所有嵌套property。返回Proxy对象,不等于原始对象。建议只操作Proxy对象,不要操作原始对象。
官方建议,对来自于服务器的数据或者注定要响应式的数据执行reactive之前,最好不要用临时变量储存原始数据,因为没有意义,而且两个变量容易让初学者引起误操作。
ref
ref说白了就是reactive({value: 原始数据})。下方代码如果打印r对象,会得到RefImpl(ref)对象,它有一个value属性指向基础类型值30
<template>
<button @click="r++">count is: {{ r }}</button>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
let r = ref(30);
return {
r,
};
},
};
</script>
```js
为什么似乎Proxy已经解决所有问题,还要有ref API呢?
因为ES的Proxy API是为引用数据类型服务的,它无法为基本数据类型提供代理。如果强行代理,Vue会有提示:value cannot be made reactive: 30。
那么为什么Vue2的defineproperty并没有区分基本数据类型和引用数据类型呢?
因为defineproperty就是Object的静态方法,它只是为对象服务的,甚至无法对数组服务,因此Vue 2弄了一个data根对象来存放基本数据类型,这样无论什么类型,都是根对象的property,所以也就能代理基本数据类型。
而Proxy能对所有引用类型代理,Vue 3也不再用data根对象,而是一个个的变量,所以带来了新问题,如何代理基本数据类型呢?并没有原生办法,只能构建一个{value: Proxy Object}结构的对象,这样Proxy也就能代理了。
问题来了,同样是响应式结构,ref跟reactive的区别是什么?
ref与reactive的区别
| 对比 | ref | reactive |
|---|---|---|
| 返回数据类型 | RefImpl对象(也叫ref对象) | Proxy对象 |
| 传入基本类型返回 | {value: 基本类型} | 禁止这么做 |
| 传入引用类型返回 | {value: Proxy对象} | Proxy对象 |
| 两者分别适用场合: |
ref可以为基本类型添加响应式,也可以为引用类型添加响应式,reactive只能为引用类型添加响应式。
对于引用类型,什么时候用ref,什么时候用reactive?
简单说,如果你只打算修改引用类型的一个属性,那么推荐用reactive,如果你打算变量重赋值,那么一定要用ref
使用组合式API的话,请一定了解“重赋值自身”和“重赋值自身属性”的区别
想在组合式API中让数据具备响应式,必须用ref,因为ref又对Proxy包装了一层,修改ref其实是修改它的value,它的value一定是响应式的,因此视图就正常更新了。
再多说一点,如果数据是服务器返回的LIST数据,而且只显示、不变更,那么最好是使用shallowRef来包装数据,可以节能。如果会有变更,那么应该用ref。
现在好像ref把引用数据类型也管起来了,到底啥时候才适合用reactive呢?很简单啊,如果你确信你只可能去改引用类型数据的属性,那么一定要用reactive,如果还有可能要整体重赋值,那还得用ref。
所以说:需要在组合式API里给变量重赋值的话,无论什么数据类型都必须用ref,不可以用reactive。
toRef / toRefs
toRef 和 toRefs 可以用来复制 reactive 里面的属性然后转成 ref,而且它既保留了响应式,也保留了引用,也就是你从 reactive 复制过来的属性进行修改后,除了视图会更新,原有 ractive 里面对应的值也会跟着更新,如果你知道 浅拷贝 的话那么这个引用就很好理解了,它复制的其实就是引用 + 响应式 ref
toRef 与toRefs的区别
toRefs可以看做批量版本的toRef。
| toRef | toRefs | |
|---|---|---|
| 用法 | toRef(Proxy, 'xxprop') | toRefs(Proxy) |
| 返回 | ObjectRefImpl对象 | 同左 |
| 作用 | 创建变量到Proxy属性的响应式连接 | 创建变量每个属性到Proxy每个属性的响应式连接 |
| 连接关系 | 一对一 | 多对多 |
toRefs的一大用途是变相解构Proxy。首先了解一个常识,Proxy如果解构,基本数据会丢失响应式。现在我既想要解构Proxy,又不想丢失响应式,怎么办?可以使用toRefs。
为什么Vue3中声明响应式对象一般用const
因为 Vue 的响应式系统是通过属性访问进行追踪的(响应式数据对象的属性的副作用函数的订阅),因此我们必须始终保持对该响应式对象的相同引用。 防止响应式被替换丢失链接
let state = reactive({ count: 0 })
// 上面的引用 ({ count: 0 }) 将不再被追踪(响应性连接已丢失!)
state = reactive({ count: 1 })
而如果使用const进行声明的话,state不允许被重新赋值。可以用声明变量上方式响应式链接丢失。防止原响应式对象在WeakMap中失去。