接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value。
vue3
中定义数据默认不是响应式的数据,需要手动将数据转化为响应式的,这里就用到了ref()
let num1 = 20 //非响应式的
import {ref} from 'vue'v
let num1 = ref(20) // 响应式的
ref()
可以将数据转为响应式数据ref(xx)
的值需要使用.value
的形式,html
模板中使用不需要.value
因为html
中默认就是通过.value
来获取值的<p ref="demo">获取ref的元素</p>
import {ref,onmounted} from 'bue'
onMounted(()=>{
let demo= ref() 这样就获取了id=demo的元素
console.log(demo.value)
})
注意!声明的变量名要跟dom元素的id一致才可以, ref不传任何参数。记得在dom挂载之后再获取
判断是不是一个ref对象
import { ref, Ref,isRef } from 'vue'
let message: Ref<string | number> = ref("我是message")
let notRef:number = 123
const changeMsg = () => {
message.value = "change msg"
console.log(isRef(message)); //true
console.log(isRef(notRef)); //false
}
let _obj = {
num: 20,
}
let objRef = ref(_obj)
console.log('ref obj', objRef.value.num)
let obj = reactive(_obj)
console.log('reactive obj', obj.num)
其实ref().value内部是跟reactive()一样的,所以说ref内部是通过reactive实现的。
reactive
针对引用类型,内部通过new Proxy
实现,因为new proxy
可以直接拦截引用类型,无法直接在基础类型进行拦截。
ref
针对基础类型和引用类型,内部会生成一个对象添加value
属性指向数据类型,然后再通过reactive
(new proxy
)对生成的对象进行拦截。达到响应式的效果。
所以为什么ref
的值需要用.value
来获取,因为内部生成一个新的带有value
属性的对象,只有对象的形式才能使用new proxy
进行拦截
作用:
在解构 reactive()得到对象的时候,将解构的数据变成响应式ref()类型.
当然解构出来的数据依旧需要通过.value的形式来操作.
常用于es6的解构赋值操作,因为在对一个响应式对象直接解构时解构后的数据将不再有响应式,而使用toRefs和toRef 可以方便解决这一问题。
let _obj = {
num: 20,
}
let obj = reactive(_obj)
//toRef
let num = toRef(obj,'num')
//toRefs
let { num } = toRefs(obj)
const handleClick = () => {
// obj.num++
// toRefs()模式
num.value++
}
toRef针对对象的单个属性,toRefs直接针对对象,记得需要用.value来获取值
const obj = {
foo: 1,
bar: 1
}
const state = toRef(obj, 'bar')
// bar 转化为响应式对象
const state = toRefs(obj)
// obj 转化为响应式对象
obj
对象是非响应式的 ,toRef/toRefs
可以将obj
转为响应式对象,但视图的更新方法在ref reactive
中有实现,toRef/toRefs
并没有更新视图的功能
toRef/toRefs
实现的大体思路是:判断是不是响应式对象,如果是直接返回,如果不是通过ObjectRefImpl()
将数据变成响应式
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue?: T[K]
): ToRef<T[K]> {
const val = object[key]
return isRef(val)
? val
: (new ObjectRefImpl(object, key, defaultValue) as any)
}
ObjectRefImpl的实现
class ObjectRefImpl<T extends object, K extends keyof T> {
public readonly __v_isRef = true
constructor(
private readonly _object: T,
private readonly _key: K,
private readonly _defaultValue?: T[K]
) {}
get value() {
这里没有监听视图变化
const val = this._object[this._key]
return val === undefined ? (this._defaultValue as T[K]) : val
}
set value(newVal) {
这里没有监听视图变化
this._object[this._key] = newVal
}
}
下面是ref
的源码实现,明显的区别在于toRef
没有视图的更新