Vue3 中ref和reactive的核心区别是什么?

Vue3 中refreactive的核心区别,这是掌握组合式 API 的关键知识点!我会从「本质差异→使用场景→代码示例→选择原则」四个维度,用通俗的语言帮你彻底分清两者,还会解决你可能遇到的 "解构丢失响应式" 等实际问题。

一、核心区别总览(先记结论)

refreactive都是 Vue3 创建响应式数据的 API,但核心定位不同:

  • ref :主打「基本类型」(String/Number/Boolean),也支持复杂类型(对象 / 数组),通过 .value 访问 / 修改;
  • reactive :主打「复杂类型」(对象 / 数组),无需 .value,直接操作属性,但不支持基本类型。

下面用表格直观对比所有差异点:

对比维度 ref reactive
适用数据类型 基本类型(优先)、复杂类型(兼容) 仅复杂类型(对象 / 数组),不支持基本类型
访问 / 修改方式 逻辑中:变量.value;模板中:直接用 逻辑 + 模板中:直接操作属性(无需.value)
解构特性 解构后仍保持响应式(需注意赋值) 直接解构会丢失响应式(需配合toRefs
新增属性支持 支持(复杂类型时,内部自动用 reactive) 支持(对象 / 数组可直接新增属性 / 元素)
顶层属性响应式 基本类型时天然支持;复杂类型时顶层属性变化支持 仅支持嵌套属性变化,顶层替换对象会丢失响应式
类型推导(TS) 自动推导,类型友好 需手动指定类型(复杂对象时),略繁琐

二、逐个差异点详解(配代码示例)

1. 适用数据类型:基本类型 vs 复杂类型

这是最核心的区别,直接决定了该选哪个 API。

ref:优先用于基本类型,兼容复杂类型
vue 复制代码
<script setup>
import { ref } from 'vue'

// ✅ 基本类型(推荐用法)
const name = ref('张三') // String
const age = ref(18) // Number
const isStudent = ref(true) // Boolean

// ✅ 复杂类型(兼容用法,内部自动转为reactive)
const user = ref({
  address: '北京',
  hobby: ['篮球']
})

// 修改数据:必须用 .value
name.value = '李四'
user.value.address = '上海' // 复杂类型时,.value 拿到的是reactive对象
user.value.hobby.push('游戏')
</script>
reactive:仅支持复杂类型,基本类型无效
vue 复制代码
<script setup>
import { reactive } from 'vue'

// ❌ 错误用法:基本类型用reactive,不会变成响应式
const age = reactive(18)
age = 20 // 毫无反应,不是响应式

// ✅ 正确用法:对象类型
const user = reactive({
  name: '张三',
  age: 18
})

// ✅ 正确用法:数组类型
const list = reactive(['苹果', '香蕉'])

// 修改数据:直接操作属性/元素
user.name = '李四'
list.push('橘子')
</script>

2. 访问方式:.value 的有无

这是新手最容易踩坑的点,记住一句话:ref需要.value,reactive不需要

ref:逻辑中必须加.value,模板中不用
vue 复制代码
<template>
  <!-- 模板中:直接用,无需.value -->
  <p>姓名:{{ name }}</p>
  <p>年龄:{{ age }}</p>
</template>

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

const name = ref('张三')
const age = ref(18)

// 逻辑中:必须加 .value 才能访问/修改
const updateUser = () => {
  name.value = '李四' // 正确:修改生效,视图更新
  age.value += 1 // 正确:年龄变成19
  // age = 19 // 错误:直接赋值会覆盖ref对象,丢失响应式
}
</script>
reactive:全程无需.value,符合直觉
vue 复制代码
<template>
  <!-- 模板中:直接用属性 -->
  <p>姓名:{{ user.name }}</p>
  <p>爱好:{{ list[0] }}</p>
</template>

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

const user = reactive({ name: '张三' })
const list = reactive(['篮球'])

// 逻辑中:直接修改属性,无需.value
const updateData = () => {
  user.name = '李四' // 正确:视图更新
  list[0] = '游戏' // 正确:视图更新
}
</script>

3. 解构特性:是否需要toRefs

解构是日常开发常用操作,但reactive直接解构会丢失响应式,ref则不会。

ref:解构后仍保持响应式
vue 复制代码
<script setup>
import { ref } from 'vue'

const user = ref({
  name: '张三',
  age: 18
})

// 解构:直接解构ref对象的属性
const { name, age } = user.value // 注意:这里解构的是user.value(reactive对象)

// 修改:name和age是ref类型,需要.value
name.value = '李四' // 正确:user.name同步更新,响应式不丢失
age.value = 20 // 正确:视图更新
</script>
reactive:直接解构丢失响应式,需用toRefs
vue 复制代码
<script setup>
import { reactive, toRefs } from 'vue'

const user = reactive({
  name: '张三',
  age: 18
})

// ❌ 错误:直接解构,丢失响应式
const { name, age } = user
name = '李四' // 视图不更新,响应式失效

// ✅ 正确:用toRefs解构,保持响应式
const { name: newName, age: newAge } = toRefs(user)
newName.value = '李四' // 正确:需要.value,视图更新
newAge.value = 20 // 正确:user.age同步更新
</script>

4. 顶层属性响应式:替换对象的差异

当需要「替换整个对象」时,refreactive的表现不同:

ref:替换整个对象仍保持响应式
vue 复制代码
<script setup>
import { ref } from 'vue'

const user = ref({ name: '张三', age: 18 })

// 直接替换整个对象:响应式不丢失
user.value = { name: '李四', age: 20 } // 正确:视图更新
</script>
reactive:替换整个对象会丢失响应式
vue 复制代码
<script setup>
import { reactive } from 'vue'

const user = reactive({ name: '张三', age: 18 })

// ❌ 错误:替换整个对象,丢失响应式
user = { name: '李四', age: 20 } // 后续修改user.name,视图不更新

// ✅ 正确:不替换对象,只修改属性
user.name = '李四'
user.age = 20 // 响应式正常
</script>

三、实际开发中的选择原则(新手直接照做)

不用纠结,按以下优先级选择即可:

  1. 基本类型(String/Number/Boolean) :优先用 ref例:const count = ref(0)const username = ref('')
  2. 复杂类型(对象 / 数组) :优先用 reactive例:const form = reactive({ username: '', password: '' })const list = reactive([])
  3. 需要解构复杂类型reactive + toRefs例:const { username, password } = toRefs(form)
  4. 需要替换整个对象 :用 ref例:接口请求后需要替换整个数据对象时,data.value = res.data
  5. TypeScript 开发
    • 基本类型:ref(自动推导类型,无需额外配置)
    • 复杂类型:reactive + 接口定义(例:const user: User = reactive({...})

总结

  1. 核心区别ref 主打基本类型(需.value),reactive 主打复杂类型(无需.value);
  2. 关键坑点reactive 直接解构丢响应式(用toRefs解决),ref 修改必须加.value
  3. 选择原则 :基本类型用ref,复杂类型用reactive,解构用toRefs,替换对象用ref

记住这 3 点,开发中就不会再混淆两者的用法啦!如果遇到具体场景不确定选哪个,不妨把数据类型和需求(是否解构、是否替换对象)列出来,对照上面的原则就能快速判断~

相关推荐
mldong4 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60615 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角6 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!6 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰7 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi8 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马9 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒10 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端