Vue3中ref与reactive的用法详解——reactive

前言

在Vue2中的响应式数据需要放入 data 函数,Vue2 会遍历 data 中的所有属性,使用的Object.defineProperty 把每个 property 全部转为 getter/setter,getter 用来收集依赖,setter 用来执行 notify,发布更新事件。

而在Vue 3的响应式系统中使用了ref和reactive 这两个核心概念,它们为开发者提供了处理响应式数据的不同方式。理解它们的特性和区别对于构建灵活、高效的Vue应用至关重要

reactive

除了ref外,Vue3还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的ref不同,reactive() 将使对象本身具有响应性。

基本用法

<template>
    <button @click="addCount">
      {{ state.count }}
    </button>
</template>

<script setup>
import { reactive } from 'vue'

const state = reactive({ count: 0 })

const addCount = () => {
    state.count++
}
</script>

相较于ref,reactive在Javascript中对数据修改时并不需要在.value属性下寻找,另外reactive的参数只能是对象或者数组或者像 Map、Set 这样的集合类型。

Proxy代理

const raw = {}
const proxy = reactive(raw)

// 代理对象和原始对象不是全等的
console.log(proxy === raw) // false

从以上代码可以看出,原始数据和reactive下的数据并不是全等的。因为reactive返回的是一个原始对象的Proxy。

// 在同一个对象上调用 reactive() 会返回相同的代理
console.log(reactive(raw) === proxy) // true

// 在一个代理上调用 reactive() 会返回它自己
console.log(reactive(proxy) === proxy) // true

为保证数据的一致性,代理对象调用reactive()仍会返回自己本身。

<script setup>
  import { reactive } from 'vue'

  const obj = {
    count: 1
  }
  const proxy = reactive(obj);
  
  proxy.count++;
  console.log(proxy.count); // 2
  console.log(obj.count);   // 2
</script>

从以上代码的运行结果说明 reactive ()代理对象发生改变时,原始数据也会跟着发生变化。

注意事项

  • reactive 的参数只能是对象或者数组或者像 Map、Set 这样的集合类型。如果是原始数据类型,控制台会报警告
  • 由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失
let state = reactive({ count: 0 })

// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
  • 当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接
const state = reactive({ count: 0 })

// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++

// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)
  • 使用 reactive 定义的响应式对象,会深度监听每一层的属性,它会影响到所有嵌套的属性。即嵌套在响应式数据中的对象不论层级都会变成响应式对象。
<script setup>
  import { reactive } from 'vue'

  let obj = reactive({
    name: 'Minato',
    a: {
      b: {
        c: 1
      }
    }
  })

  console.log("obj: ", obj) //obj: Proxy(Object){name:'Minato',a:{……}}
  console.log("obj.name: ", obj.name) //'Minato'
  console.log("obj.a: ", obj.a) //Proxy(Object){b:{……}}
  console.log("obj.a.b: ", obj.a.b) //Proxy(Object){c:{……}}
  console.log("obj.a.b.c: ",obj.a.b.c) //1
</script>
  • 若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,我们可以使用 shallowReactive()。
<script setup>
  import { shallowReactive } from 'vue'

  let obj = shallowReactive({
    name: 'Echo',
    a: {
      b: {
        c: 1
      }
    }
  })

 console.log("obj: ", obj) //obj: {name:'Minato',a:{……}}
 console.log("obj.name: ", obj.name) //'Minato'
 console.log("obj.a: ", obj.a) //{b:{……}}
 console.log("obj.a.b: ", obj.a.b) //{c:{……}}
 console.log("obj.a.b.c: ",obj.a.b.c) //1
</script>

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值