持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情
ref(primitive|Object)
ref接受一个内部值并返回一个响应式且可变的ref对象。ref对象只有一个value属性,指向内部的值。
import {ref} from 'vue'
let msg = ref < string > ('hello world')
let text: string = 'I am Text'
像上面这样,变量msg就被定义成一个响应式的变量,而text则是一个普通的字符串。
开头也说了,ref返回的是一个响应式且可变的ref对象,所以如果我们想要改变msg的值,不能直接给它赋值,而是要给它的value属性赋值。
// msg = 'hi world' // 错误
msg.value = 'hi world' // 正确
一般会使用ref将 原始类型 的值变为响应式的,像字符串、数值、布尔等等,而像对象、数组这些我们则应该使用reactive去将它们转变成响应式的。 但是,我们还是可以使用ref去转换对象和数组的,像下面这样使用
let arr = ref<number[]>([]);
let obj = ref({
name: "mac",
});
// 改变它们的值
const change = () => {
arr.value = [1, 2, 3];
obj.value.name = 'xxx'
};
像上面这样,改变它们的值同样会在页面上反映出来。
为什么ref也可以转变复杂数据类型呢?通过源码可以知道,我们使用ref包裹复杂数据类型的时候,它会调用toReactive,而toReactive则调用reactive,相当于是Vue内部帮我们用reactive去转变了。
在JS中改变以及使用被ref转变后的响应式变量需要像下面这样使用
let num = ref < number > (1)
const two = num.value + 1 // 使用(读取)
num.value++ // 改变
但是在template中使用则不需要加上.value,因为vue会自动解包。
<div>{{num}}</div>
isRef(r)
判断参数r是否为ref对象
function isRef(r) {
return !!(r && r.__v_isRef === true);
}
通过源码可以知道,当我们使用ref的时候,它会调用createRef,而createRef则会先调用isRef判断是否已经是ref对象了,如果是的话则直接返回,如果不是再将其转变成ref对象。
function createRef(rawValue, shallow) {
if (isRef(rawValue)) {
return rawValue;
}
return new RefImpl(rawValue, shallow);
}
shallowRef()
创建一个跟踪自身.value变化的ref,但是不会使其值(.value的值)变成响应式。这个可以用于节省性能。
import {shallowRef} from 'vue'
let msg = shallowRef({
name: 'mac'
})
const change = () => {
msg.value.name = 'xxx' // 这样页面上是不会改变的
// 当然,只是页面上没有跟着变,实际上值已经改变了
}
const change2 = () => {
msg.value = {name: 'xxx'} // 这样页面也会跟着变
}
triggerRef()
强制更新页面DOM,常和shallowRef搭配使用。比如说,上面我们知道使用shallowRef改变.value后面的值是不会在页面上反映出来的,但是在代码中却是实实在在被改变了,这个时候我们可以使用triggerRef去强制更新DOM,让页面上的值也改变
let msg = shallowRef({
name: 'mac'
})
const change = () => {
msg.value.name = 'xxx' // 这样页面上是不会改变的
triggerRef() // 强制更新,这样页面也改变了
}
这里还有一种情况,看下面的代码
let msg = ref('hello')
let man = shallowRef({
name: 'mac'
})
const change = () => {
man.value.name = 'xxx'
msg.value = 'hi'
}
像上面这种情况,man的name属性值的改变也会在页面上显示出来。通过源码可以知道,triggerRef是调用了triggerRefValue,而通过ref包裹的值在set的时候也会调用triggerRefValue(看最上面的RefImpl类),所以导致shallowRef包裹的值也在页面上更新了。
customRef
自定义ref,这个是一个工厂函数,要求我们返回一个对象,并且实现get和set
从下面的代码中可以知道,customRef接收一个工厂函数,函数返回一个对象,对象中有get和set,工厂函数factory有两个参数,一个是track,一个是trigger,track用于帮我们收集依赖,而trigger则是帮我们触发更新。
const {get, set} = factory(() => trackRefValue(this), () => triggerRefValue(this));
使用实例
当我们执行change的时候,改变msg的值,同时触发set,会在控制台输出set。