跟着文档学VUE3(二)

87 阅读3分钟

Vue 响应式编程核心揭秘:掌握 ref 与 reactive 的底层逻辑

关键词:Vue3响应式、ref、reactive、Vue Composition API、响应式原理

🔍 一、如何声明响应式状态

使用 [ref()]

✅ ref() 的三大核心细节:

特性描述
入参接受任意类型的数据(原始值或对象)
返回值返回一个带有 .value 属性的响应式对象
模板中使用在 <script setup> 中无需返回即可直接使用;在模板中自动解包 .value
import { ref } from 'vue'

export default {
  // `setup` 是一个特殊的钩子,专门用于组合式 API。
  setup() {
    const count = ref(0)

    // 将 ref 暴露给模板
    return {
      count
    }
  }
}

💡 小贴士:

  • 使用 <script setup> 语法时,可以直接在模板中使用 ref 变量而无需 return
  • 支持在事件中直接修改 ref,如 count.value++

🧠 二、为何使用响应式状态 ref

🔄 Vue 响应式工作原理四步走:

  1. 首次渲染:Vue 会追踪所有被使用的 ref
  2. 数据变化:当 .value 被修改时触发 setter => ref 被修改时,它会触发追踪它的组件的一次重新渲染。
  3. 依赖收集:通过 getter 进行依赖追踪 => 在ref函数返回的对象内部,Vue 在它的 getter 中执行追踪,在它的 setter 中执行触发
  4. 视图更新:通知组件重新渲染 => 与普通变量不同,你可以将ref 传递给函数,同时保留对最新值和响应式连接的访问。

🧪 看似简单的 ref,背后却有复杂的机制支撑:

// 伪代码,不是真正的实现
const myRef = {
  _value: 0,
  get value() {
    track()
    return this._value
  },
  set value(newValue) {
    this._value = newValue
    trigger()
  }
}

⚡️ 优势对比:

普通变量ref
无法监听变化自动追踪依赖
不支持跨函数传递可以安全地传给其他函数
不具备响应性是 Vue 响应式系统的核心单元

📦 三、深层响应式 vs 浅层响应式

🔁 深层响应式(默认行为)

  • 对象/数组内部嵌套修改也能被检测到
  • 原理:Vue 内部自动调用了 reactive() 来包装对象
const user = reactive({
    profile: {
      name: 'Tom'
    }
}) 
user.profile.name = 'Jerry'  // 会被检测到

🌊 浅层响应式(使用 shallowRef / shallowReactive

  • 只追踪顶层属性变化
  • 适用于性能敏感场景或大型对象
const shallUser = shallowReactive({
    profile: {
      name: 'Tom'
    }
}) 
user.profile.name = 'Jerry'  // 不会被检测到

🕒 四、DOM更新时机 —— nextTick() 的妙用

Vue 的 DOM 更新是异步进行的,它会在下一个 tick 批量更新所有变更。

  • nextTick() => 如果需要等到DOM更新完成只会再执行额外的代码
import { nextTick } from 'vue'

async function increment() {
  count.value++
  await nextTick()
  // 现在 DOM 已经更新了
}

📌 应用场景

  • 获取更新后的 DOM 元素尺寸
  • 动态加载内容后需要操作 DOM
  • 表单校验反馈等 UI 后续处理

🧩 五、reactive() 详解:让对象原生具有响应性

🔍 ref vs reactive 对比:

特性refreactive
数据类型支持任意类型仅支持对象类型(对象,数组和Map,Set等集合类型)
响应方式包装成对象返回 Proxy 代理
解构问题✔️ 安全解构❌ 解构会丢失响应性
多次调用每次返回新 ref同一个对象返回相同代理

🚫 注意事项:

  • reactive() 不支持原始类型(如 number、string),需用 ref
  • 对同一个对象多次调用 reactive() 返回的是同一个代理

📄 六、在模板中使用响应式状态的注意事项

⚠️ 解包陷阱:顶级 ref 才能自动解包

const object = { id: ref(1) }
// ❌
{{ object.id + 1 }}

// ✅
const { id } = object
{{ id + 1 }}

// 📝 文本插值始终自动解包:
{{ object.id }} // 1

🎯 总结:响应式开发的黄金法则

场景推荐方案
基础状态管理ref()
复杂对象/嵌套结构reactive() 或 ref(object)
需要解构使用优先使用 ref()
性能敏感型对象使用 shallowRef / shallowReactive
DOM 更新回调使用 nextTick() 控制流程