Vue3中关于ref和reactive的区别分析

 更新时间:2023年06月28日 09:00:05   作者:狂砍2分4篮板  
这篇文章主要介绍了vue3关于ref和reactive的区别分析,文中通过示例代码介绍的非常详细,具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

一、reactive

数据类型

reactive()可用于创造一个响应式对象,它接受一个参数,这个参数的类型是一个重点,接下来我们先看看Vue3的源码里是怎么处理的。

function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  if (!isObject(target)) {
    if (__DEV__) {
      console.warn(`value cannot be made reactive: ${String(target)}`)
    }
    return target
  }
  // ...
}

Vue3主要是调用createReactiveObject函数来创建reactive对象,从源码里可以看到,该函数会首先判断reactive()传入的参数是不是一个对象,如果不是则不做任何处理,直接返回原值,同时开发环境下会在控制台输出一句警告。所以严格上来说,reactive()并不是像有些人说的不能传入基本类型的参数,它可以传,只是这种数据会失去响应式。

let name = reactive('张三')
setTimeout(() => {
  name = '李四'
  console.log(name, 'name') // 李四
}, 3000)
<template>
  <h1>{{ name }}</h1>
</template>

上面模板里仍然显示的是张三,因为name没有响应式不会触发视图更新。

原始数据与响应式数据

我们可以先定义一个原始对象,再将对象传入reactive(),此时原始对象和响应式对象会互相干扰。

let data = { name: '张三' } // 原始对象
let state = reactive(data)
setTimeout(() => {
  state.name = '李四'
  console.log(data.name) // 李四
}, 2000)

修改响应式对象state.name的值,原始对象data.name也会同步变化。

反过来也是一样,修改data.namestate.name也会同步变化,但需要注意的是:这种情况下虽然state.name发生了改变但视图并不会更新

let data = { name: '张三' }
let state = reactive(data)
setTimeout(() => {
  data.name = '李四'
  console.log(state.name) // 李四,但template里仍为张三
}, 2000)
</script>
<template>
  <h1>{{ state.name }}</h1>
</template>

所以如果你是通过定义一个对象再将对象传入reactive的话,建议始终是对响应式对象进行操作而不是原始数据。

二、ref

数据类型

export function ref(value?: unknown) {
  return createRef(value, false)
}

从源码里可以知道,ref()接受一个参数,参数可以是任意类型,这也是ref与reactive的区别之一,不管是基本类型还是引用类型ref都具备响应式,另外ref要通过.value进行取值。

let name = ref('张三') // 可以是基本类型
// 也可以是引用类型
let user = ref({
  name: '张三',
  age: 18
})
console.log(name.value)
console.log(user.value)

原始数据与响应式数据

refreactive一样,修改原始数据或响应式数据都会同步改变对方的值,且在修改原始对象时都无法触发视图更新。

ref也可能是一种reactive

function createRef(rawValue: unknown, shallow: boolean) {
  if (isRef(rawValue)) {
    return rawValue
  }
  return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
  private _value: T
  private _rawValue: T
  public dep?: Dep = undefined
  public readonly __v_isRef = true
  constructor(value: T, public readonly __v_isShallow: boolean) {
    this._rawValue = __v_isShallow ? value : toRaw(value)
    this._value = __v_isShallow ? value : toReactive(value)
  }
  get value() {
    trackRefValue(this)
    return this._value
  }
  set value(newVal) {
    const useDirectValue =
      this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
    newVal = useDirectValue ? newVal : toRaw(newVal)
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = useDirectValue ? newVal : toReactive(newVal)
      triggerRefValue(this, newVal)
    }
  }
}

通过源码可以知道,ref是通过RefImpl这个类来创建的,而在RefImpl内部会调用toReactive函数,如果不是基本类型的数据,会将其转换成reactive

可重新赋值对象

使用reactive时,对响应式对象重新赋值是会失去响应式的。

let state = reactive({ name: '张三' })
setTimeout(() => {
  state = { name: '李四'}
  console.log(state.name) // 李四,数据变更了但视图不会更新
}, 2000)

ref则没有这种问题。

let state = ref({ name: '张三' })
setTimeout(() => {
  state.value = { name: '李四'}
  console.log(state.value.name) // 数据变更,同时视图也会更新
}, 2000)

使用watch监听ref对象需要deep

let state = ref({ name: '张三' })
setTimeout(() => {
  state.value.name = '李四'
}, 2000)
watch(state, () => {
  console.log(state.value.name)
}, { deep: true })

reactive不加deep: truewatch也会触发,而ref则需要手动加上。

小结

  • 对于响应式而言,ref支持对象类型和基本类型,而reactive只支持对象类型
  • 当ref是对象类型的时候,本质上也是一个reactive
  • 对象类型的ref和reactive,其响应式底层原理都是Proxy

以上就是Vue3中关于ref和reactive的区别分析的详细内容,更多关于vue3 ref 和reactive的资料请关注脚本之家其它相关文章!

相关文章

  • 深入浅析Vue.js计算属性和侦听器

    深入浅析Vue.js计算属性和侦听器

    这篇文章主要介绍了Vue.js计算属性和侦听器的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-05-05
  • 解决vue里碰到 $refs 的问题的方法

    解决vue里碰到 $refs 的问题的方法

    本篇文章主要介绍了解决vue里碰到 $refs 的问题的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • vue中集成省市区街四级地址组件的实现过程

    vue中集成省市区街四级地址组件的实现过程

    我们在开发中常会遇到选择地址的需求,有时候只需要选择省就可以,有时候则需要选择到市、县,以至于乡镇,甚至哪个村都有可能,下面这篇文章主要给大家介绍了关于vue中集成省市区街四级地址组件的相关资料,需要的朋友可以参考下
    2022-12-12
  • Vue3解析markdown并实现代码高亮显示的详细步骤

    Vue3解析markdown并实现代码高亮显示的详细步骤

    Vue的markdown解析库有很多,如markdown-it、vue-markdown-loader、marked、vue-markdown等,这篇文章主要介绍了Vue3解析markdown并实现代码高亮显示,需要的朋友可以参考下
    2022-07-07
  • vue element插件this.$confirm用法及说明(取消也可以发请求)

    vue element插件this.$confirm用法及说明(取消也可以发请求)

    这篇文章主要介绍了vue element插件this.$confirm用法及说明(取消也可以发请求),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 详解Vue3框架的搭建及工程目录

    详解Vue3框架的搭建及工程目录

    文章介绍了如何使用Node.js搭建Vue工程,并对Vue工程目录进行了详细解读,包括各种文件夹和文件的作用,此外,还讲解了如何设置网页标题和全局样式,以及如何配置路由,感兴趣的朋友一起看看吧
    2025-03-03
  • Vue.js轮播图走马灯代码实例(全)

    Vue.js轮播图走马灯代码实例(全)

    这篇文章主要介绍了Vue.js轮播图走马灯,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • vue中$refs, $emit, $on, $once, $off的使用详解

    vue中$refs, $emit, $on, $once, $off的使用详解

    这篇文章主要介绍了vue中$refs, $emit, $on, $once, $off的使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • Vue3学习之事件处理详解

    Vue3学习之事件处理详解

    Vue事件处理是每个Vue项目的必要方面。 它用于捕获用户输入,共享数据以及许多其他创造性方式。本文将通过简单的示例为大家讲解了Vue3中事件处理的使用,需要的可以参考一下
    2022-12-12
  • Vue2父子组件传值举例详解

    Vue2父子组件传值举例详解

    这篇文章主要给大家介绍了关于Vue2父子组件传值的相关资料,Vue 2.0 中父子组件之间的传值可以通过属性(prop)和事件(event)实现,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05

最新评论