【从零开始学习Vue|第二篇】响应式基础

8 阅读3分钟

1. 基本定义

  • 在Vue3中的Composition API中,ref和reactive都是用来创建响应式数据的核心函数
函数作用
ref用于创建一个响应式的引用对象,适用于基本类型(string/number/boolean) 或 单个值
reactive用于创建一个响应式的对象(或数组),对对象/数组进行深层响应式包装
  1. 使用数据类型不同
    1. ref:适合基本类型+单个值
import { ref } from 'vue'

const count = ref(0)           // number
const name = ref('Alice')      // string
const isLoading = ref(false)   // boolean
  • 虽然ref也可以包裹对象,但是不推荐
    1. reactive: 只适合对象/数组
import { reactive } from 'vue'

const state = reactive({
  count: 0,
  name: 'Alice',
  items: [1, 2, 3]
})
  • 其中不能用reactive(0) 或reaxctive('hello')会报错
  1. 访问和修改方式不同
读取值修改值
refcount.valuecount.value = 1
reactivestate.countstate.count = 1
const count = ref(0)
const state = reactive({ count: 0 })

console.log(count.value)     // 0
console.log(state.count)     // 0

count.value++                // ✅ 正确
state.count++                // ✅ 正确

// ❌ 错误!这样不会触发响应式更新
count = 1                    // 报错或无效(因为 count 是 Ref 对象)
  • 在模版中,Vue会自动解包count,所以可以直接写{{ count }},不用 .value 。
  1. 替换整个对象的能力
  • ref: 可以整体替换引用
const user = ref({ name: 'Tom' })
user.value = { name: 'Jerry' } // ✅ 完全替换,响应式依然有效
  • reactive:不能直接替换整个对象
const user = reactive({ name: 'Tom' })
user = { name: 'Jerry' } // ❌ 报错!user 是常量,且失去响应式

如果想重置,必须逐个属性赋值:

Object.assign(user, { name: 'Jerry' })
  1. 内部实现机制
内部结构响应式原理
ref{ value: ... }包装对象通过 .value的 getter/setter 触发依赖收集
reactiveProxy 代理原对象使用 ES6 Proxy拦截对象所有属性的读写
  • ref本质上是对. value 属性做响应式
  • reactive 是对整个对象做深层代理
  1. 在模版中的使用体验
  • 两者在模板中几乎无差别,因为 Vue 会自动解包 ref
<template>
  <p>{{ count }}</p>        <!-- ref 自动 .value -->
  <p>{{ state.count }}</p>  <!-- reactive 直接访问 -->
</template>

<script setup>
import { ref, reactive } from 'vue'
const count = ref(0)
const state = reactive({ count: 0 })
</script>

2. 如何选择以及使用建议

场景推荐
基本类型(数字、字符串、布尔值)ref
单个对象/数组,且不需要频繁替换整个对象reactive
需要传递给子组件(props / emit)ref(更灵活)
返回多个响应式变量(组合函数)ref(方便解构)
大型状态对象(如 store)reactive(结构清晰)
  • 不确定的时候,优先使用ref调用(更通用,更安全
  • 管理复杂对象的时候,用reactive(代码更简洁

3. 常见误区

3.1. reactive 可以监听基本类型?

const num = reactive(0) // ❌ 无效!控制台警告

3.2. 在setup()外直接用ref值?

const count = ref(0)
setInterval(() => {
  count++ // ❌ 忘记 .value
}, 1000)
// 应该:count.value++

3.3. 解构 reactive 会失去响应式

const state = reactive({ count: 0 })
const { count } = state // ❌ count 变成普通 number,失去响应式!

// ✅ 正确做法:用 toRefs
import { toRefs } from 'vue'
const { count } = toRefs(state) // count 仍是 ref
特性refreactive
适用类型基本类型、对象、数组仅对象、数组
访问方式.value直接属性访问
模板中是否需 .value❌ 自动解包❌ 直接用
可整体替换❌(需用 Object.assign
解构是否保持响应式✅(本身就是独立 ref)❌(需 toRefs
内部实现{ value: ... } + getter/setterProxy 代理
推荐场景通用、简单值、组合函数返回复杂状态对象