vue3 ref reactive区别

1.可接受的原始数据类型不同

   ref() reactive()都是接收一个普通的原始数据,再将其转换为响应式对象,例如上面代码中的userage。却别在于:ref可以同时处理基本数据类型和对象,而reactive只能处理处理对象不支持基本数据类型。

const numberRef = ref(0);           // OK
const objectRef = ref({ count: 0 }) // OK

//TS2345: Argument of type 'number' is not assignable to parameter of type 'object'.
const numberReactive = reactive(0);
const objectReactive = reactive({ count: 0}); // OK

这是因为二者响应式数据实现的方式不同:

  • ref是通过一个中间对象RefImpl持有数据,并通过重写它的set和get方法实现数据劫持的,本质上依旧是通过Object.defineProperty RefImplvalue属性进行劫持。
  • reactive则是通过Proxy进行劫持的。Proxy无法对基本数据类型进行操作,进而导致reactive在面对基本数据类型时的束手无策。

2.返回值类型不同

  

const count1 = ref(0)
const count2 = reactive({count:0})
console.log(count1)
console.log(count2)

结果为:

RefImpl {__v_isShallow: false, dep: undefined, __v_isRef: true, _rawValue: 0, _value: 0} 
Proxy(Object) {count: 0}

ref()返回的是一个持有原始数据的RefImpl实例。而reactive()返回的类型则是原始数据的代理Proxy实例

3.访问数据的方式不同

  • ref()返回的是RefImpl的一个实例对象,该对象通过_value私有变量持有原始数据,并重写了value的get方法。因此,当想要访问原始对象的时候,需要通过xxx.value的方式触发get函数获取数据。同样的,在修改数据时,也要通过xxx.value = yyy的方式触发set函数。
  • reactive() 返回的是原始对象的代理,代理对象具有和原始对象相同的属性,因此我们可以直接通过.xxx的方式访问数据
const objectRef = ref({ count: 0 });
const refCount = objectRef.value.count;

const objectReactive = reactive({ count: 0}); 
const reactiveCount = objectReactive.count;

总结:ref需要通过value属性间接的访问数据(在templates中vue做了自动展开,可以省略.value),而reactive可以直接访问。

另:

        ref借助reactive实现对Object类型数据的深度监听

constructor(value: T, public readonly __v_isShallow: boolean) {
    this._rawValue = __v_isShallow ? value : toRaw(value)
    this._value = __v_isShallow ? value : toReactive(value)
}

export const toReactive = <T extends unknown>(value: T): T =>
  isObject(value) ? reactive(value) : value

  ref在发现被监听的原始对象是Object类形时,会将原始对象转换成reactive并赋值给_value属性。而此时ref.value返回的并不是原始对象,而是它的代理。

//验证
const refCount = ref({count:0})
console.log(refCount.value)
//输出结果:
//Proxy(Object) {count: 0}

结论:ref()在原始数据位Object类形时,会通过reactive包装原始数据后再赋值给_value。

4.对侦听属性的影响不同

   ref watch观察

let refCount = ref({count:0})
watch(refCount,() => {
     console.log(`refCount数据变化了`)
})
refCount.value = {count:1}
//输出结果:
//refCount数据变化了

watch()可以检测到ref.value的变化。然而,继续执行如下代码

let refCount = ref({count:0})
watch(refCount,() => {
    console.log(`refCount数据变化了`)
})
refCount.value.count = 1

这次watch()没有监听到refCount的数据变化——watch()默认情况下不会深入观察 ref。若要watch深入观察ref,则需要修改参数如下:

watch(refCount, () => { 
  console.log('reactiveCount数据变化了!')
}, { deep: true })

而对于reactive而言,无论你是否声明deep: truewatch都会深入观察。

结论:watch()默认情况下只监听ref.value的更改,而对reactive执行深度监听。

总结和用法

  1. ref可以存储原始类型,而reactive不能。
  2. ref需要通过<ref>.value访问数据,而reactive()可以直接用作常规对象。
  3. 可以重新分配一个全新的对象给refvalue属性,而reactive()不能。
  4. ref类型为Ref<T>,而reactive返回的反应类型为原始类型本身。
  5. 基于第四条,ref可以自身管理依赖而reactive则借助全局变量以键值对的形式进行管理。
  6. watch默认只观察refvalue,而对reactive则执行深度监听。
  7. ref默认会用reactive 对象类型的原始值进行深层响应转换。
  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值