一. ref、toRef、toRefs推荐用法
- setup里合成函数返回响应式对象时,使用toRefs(直接解构reactive对象会失去响应式)
- reactive实现对象的响应式,ref实现值类型响应式 (不是非要这样用,主要是为了定义更清晰)
- setup中返回toRefs(reactive对象)
- ref变量命名使用变量名+Ref(项目中总结,这样能知道.value是否ref返回)
二.为什么需要ref?
- 值类型会丢失响应式,所以用ref来定义值类型使其成为响应式,区分没有响应式的普通变量
- 对于第1点有同学会说了让值类型成为响应式用reactive也可以实现为啥还要有ref,但比如在setup、computed里都有可能返回值类型,需要响应式,如下列场景我们会经常遇到:
const state = reactive({
count: 20,
name: '金卡'
})
// computed 返回的是一个类似于 ref 的对象,也有 .value
const countNew = computed(() => {
return state.count + 1
})
通过上述代码可以看到,如果使用reactive来赋予值类型响应式,仍然会遇到很多场景需要返回一个值类型,所以ref应运而生就是顺理成章的事情。
- Vue3不定义ref,框架使用者会自造ref,可能会造成代码混乱,不利于维护
三.ref为什么会有.value?
想必很多同学和我一样,通过ref定义的响应式变量在setup里使用是各种.value满天飞,写多了有点烦。但实际上vue3这样设计是有其原理合理性的,下面我就来解释这种用法的原因:
1.ref实际上是一个对象,这个对象通过属性value来存储值
2.ref通过.value的set和get来实现响应式
直白点说,也就是ref必须通过一个对象来实现响应式,而value就是这个对象的一个属性。下面我们通过一些模拟代码来具体解释一下以上2点。
首先我们使用值类型来尝试模拟ref的实现:(并非真实实现,只是关于.value部分的模拟)
const refFun = (getter)=> {
let ref = 0 // 这里ref为值类型
setTimeout(() => {
ref = getter()
}, 1000);
return ref
}
let a
a = refFun (() => 100)
我们执行上面代码,然后过1秒之后再执行a,发现在setTimeout这个异步中修改的的值,a并没有成功更新为100,仍然是初始值0。
接下来我们用对象也就是引用类型来尝试模拟ref的实现:
const refFun = (getter)=> {
const ref = {
value:0
} // 这里ref为引用类型
setTimeout(() => {
ref.value = getter()
}, 1000);
return ref
}
let a = {}
a = refFun (() => 100)
我们惊喜的发现,1秒后定义在对象里的value值,成功更新为100!
看到这想必同学们也明白了为啥ref会有.value了,一句话总结就是:ref运用了引用类型是浅拷贝的基本特性,来配合实现数据的响应式。