- 文件目录:packages/reactivity/src/ref.ts
- 作用:
- 可以将值、refs、getters 规范化为 refs
- 也就可以将响应式对象属性,创建一个对应的ref。这样创建的ref与其源属性保持同步,改变源属性的值,将更新 ref 的值;改变ref的值,也更新源属性的值。
- 源码
function toRef(source, key?, defaultValue?) {
if (isRef(source)) {
// 是ref对象,直接返回
return source
} else if (isFunction(source))) {
// 是函数,创建只读的getter返回 new GetterRefImpl
return new GetterRefImpl(source)
} else if (isObject(source) && arguments.length > 1) {
// 对象属性签名 new ObjectRefImpl
return
```js
function
```(source, key!, defaultValue)
} else {
// 创建 ref 对象返回
return ref(source)
}
}
- 核心类
class ObjectRefImpl{
constructor(
private readonly _object,
private readonly _key,
private readonly _defaultValue
) {}
get value() {
const val = this._object[this._key]
return (this._value = val === undefined ? this._defaultValue !: val)
}
set value(newValue) {
this._object[this._key] = newVal
}
get dep(): Dep | undefined {
return getDepFromReactive(toRaw(this._object), this._key)
}
}
function propertyToRef(source, key, defaultValue?) {
const val = source[key]
return isRef(val) ? val : (new ObjectRefImpl(source, key, defaultValue))
}
使用
- 规范化签名:
/** 按原样返回现有的 ref **/
const name = ref("张三");
const nameToRef = toRef(name);
console.log("方法:", nameToRef.value); // 张三
/** 创建 **只读 ref**,当调用 .value 时,会调用此 **getter 函数** **/
function testToRef() {
const state = () => "张三";
return toRef(state);
}
console.log("方法:", testToRef().value); // 张三
console.log("方法:", testToRef().value = "lisi"); // 无法为“value”赋值,因为它是只读属性。
/** 非函数值创建ref **/
const valueToRef = toRef(1);
console.log("值:", valueToRef.value); // 1
- 对象属性签名
const state = reactive({ foo: 1, bar: 2 })
// 双向 ref,会与源属性同步
const fooRef = toRef(state, "foo");
console.log("foo ref对象:", fooRef); // Ref<1>
// 更改 ref 会更新源属性
fooRef.value++;
console.log("foo value", fooRef.value); // 2
console.log("state value", state.foo); // 2
// 更改源属性也会更新 ref
state.foo++;
console.log("foo value", fooRef.value); // 3
console.log("state value", state.foo); // 3
注意
- 不同于
const fooRef = ref(state.foo)
// 这个 fooRef 不会与 state 建立同步,因为这个 ref() 接收了一个纯数值。
- 使用 toRef() 这个函数在你想把一个 prop 的 ref 传递给一个组合式函数时会有用
<script setup>
import { toRef } from "vue"
const props = defineProps()
// 将 props.foo 转换为 ref,然后传入一个组合式函数
useSomeFeature(toRef(props, 'foo))
// getter 语法
useSomeFeature(toRef(() => props.foo))
</script>