前言
toRef有什么作用呢?官方文档toRef的解释: 可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。
toRef有什么用呢?
和之前一样, 通过vue3源码测试一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="../vue/dist/vue.global.js"></script>
<script>
let { ref, effect, toRef, reactive } = Vue
let state = reactive({
name: 'vvv'
})
let name = toRef(state, 'name')
console.log(name);
effect(() => {
app.innerHTML = name.value
})
setTimeout(() => {
name.value = 'vvv2'
}, 2000)
</script>
</body>
</html>
打开浏览器, 看看测试的结果
可以看到通过toRef后返回的是一个
ObjectRefImpl实例, 可以知道toRef的作用如名字一样,将值转化为ref
toRef的实现
toRef的定义
export const toRef = (object, key, defaultValue?) => {
// 将一个对象的值转化为ref形式
const val = object[key]
return isRef(val) ? val : new ObjectRefImpl(object, key, defaultValue)
}
isRef在上一篇vue3源码 - ref篇有解释, 其作用是判断是不是已经ref过了
核心ObjectRefImpl类
// toRef核心
class ObjectRefImpl {
public readonly __v_isRef = true
constructor(private readonly _object, private readonly _key, private readonly _defaultValue?) {}
get value() {
const val = this._object[this._key] // 取值
return val === undefined ? this._defaultValue : val // 是否去默认值
}
set value(newVal) {
this._object[this._key] = newVal // 设置值
}
}
或许有人会问,这里为什么会不用track(收集依赖) 和trigger(触发依赖)呢?
这是因为toRef主要针对对象是已经响应式过的, 具体可以看官方文档toRef的解释
测试toRef
新建一个toRef.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="../node_modules/@vue/reactivity/dist/reactivity.global.js"></script>
<script>
let { ref, effect, toRef, reactive } = VueReactivity
let state = reactive({
name: 'vvv'
})
let name = toRef(state, 'name')
console.log(name);
effect(() => {
app.innerHTML = name.value
})
setTimeout(() => {
name.value = 'vvv2'
}, 2000)
</script>
</body>
</html>
打开浏览器, 看看我们实现的怎么样
为了具有辨识度, 我在
ObjectRefImpl添加了前缀My
toRefs的实现
相信大家在项目中用的最多的是toRefs, 因为toRef只能转化一层,所以用的会相对比较少
那么下面就让我们一起来实现toRefs吧
export const toRefs = (object) => {
// 循环遍历逐渐toRef
let ret = isArray(object) ? new Array(Object.length) : {}
for (let key in object) {
ret[key] = toRef(object, key)
}
return ret
}
toRefs的实现还是相对来说比较简单的, 循环遍历逐渐toRef即可
测试toRefs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="../node_modules/@vue/reactivity/dist/reactivity.global.js"></script>
<script>
let { ref, effect, toRef, reactive, toRefs } = VueReactivity
let state = reactive({
name: 'vvv',
age: 18
})
let my = toRefs(state)
console.log(my.name);
console.log(my.age);
effect(() => {
app.innerHTML = my.name.value + '=====' + my.age.value
})
setTimeout(() => {
my.name.value = 'vvv2'
my.age.value = '19'
}, 2000)
</script>
</body>
</html>
现在可能
toRefs用的也相对比较少了, 毕竟现在出了setup语法糖, 不用在return出去了, 不过我相信, 学到总比没学到好, 相信自己会用到的
toRef 和 toRefs已经实现了, vue3源码其他相关的实现静待下一篇哟
最后
如果觉得本文对你有帮助,记得点赞👍🏻 、 收藏⭐️ 加关注➕哟