跳转至

ref和reactive

在 Vue 3 中,refreactive 是响应式系统的两个核心 API。它们都用于创建响应式的数据对象,使得当数据变化时,视图也能自动更新。但使用上有区别,尤其在处理异步请求获取数据后赋值的场景时,更要注意。


一、refreactive 的区别和使用

ref 是什么?

  • ref 用来创建基本类型(如数字、字符串、布尔值)或单个对象/数组的响应式引用。
  • ref 返回的是一个带有 .value 属性的对象。

示例:

import { ref } from 'vue'

const count = ref(0)

count.value++ // 修改值
console.log(count.value) // 获取值

⚠️:不管是基本类型还是对象、数组,用 ref 包装后,都必须通过 .value 访问和修改。


reactive 是什么?

  • reactive 用来创建对象类型的响应式数据(对象、数组、嵌套结构)。
  • 直接使用对象属性,不需要 .value

示例:

import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: {
    name: 'Tom',
    age: 20
  }
})

state.count++ // 响应式更新

⚠️:reactive 不能直接用于基本类型(数字、字符串等),必须是对象或数组。


二、数据请求后赋值的处理

在项目开发中,我们经常是请求接口后,动态获取数据赋值到响应式变量中。这就涉及初始化时是否要写出键值的问题。


✅ 是否要初始化属性?

✅ 建议初始化 至少写好结构,理由如下:

  1. 防止模板中访问 undefined 报错
  2. 保持响应式引用一致
  3. 避免 watch/computed 无法监听到新属性

示例 1:使用 ref 初始化为对象

import { ref, onMounted } from 'vue'

const userInfo = ref({
  name: '',
  age: null,
  gender: ''
})

onMounted(async () => {
  const res = await fetchUserData()
  userInfo.value = res.data
})

如果初始化为 {},也可以,但推荐提前写出结构,避免页面绑定时出现 userInfo.value.name 报错。


示例 2:使用 reactive 初始化

import { reactive, onMounted } from 'vue'

const userInfo = reactive({
  name: '',
  age: null,
  gender: ''
})

onMounted(async () => {
  const res = await fetchUserData()
  Object.assign(userInfo, res.data)
})

使用 Object.assign 替换响应式对象的属性值,而不是直接替换整个对象(这样会失去响应式)。


三、ref vs reactive 在请求后的赋值注意点

场景 使用 ref 使用 reactive
基本类型 ✅ 推荐 ❌ 不适合
对象或数组 ✅ 可以,但访问要 .value ✅ 推荐使用
数据整体替换 ✅ 直接替换 .value ❌ 不要直接替换,用 Object.assign
初始化 可以是空,但建议写结构 建议写结构,避免响应式失效
模板使用 需要 .value(除非通过 setup() return 解包) 直接访问属性即可

四、模板中的使用区别

使用 ref

<template>
  <div>{{ userInfo.value.name }}</div>
</template>

使用 reactive

<template>
  <div>{{ userInfo.name }}</div>
</template>

⚠️ 当然,如果你在 setup() 里用 return { userInfo },Vue 会自动对 .value 进行“解包”,让模板里不需要加 .value


五、总结建议

✅ 对象/数组数据建议用 reactive

  • 初始化时尽量写出属性结构,避免 undefined;
  • 赋值时使用 Object.assign 而不是整个对象替换。

✅ 基本类型或需整体替换对象/数组时用 ref

  • 使用 .value 访问;
  • 可以整体替换 ref.value = xxx

如果你正在开发页面,有异步请求场景,我可以帮你写个具体 demo,对比两种写法。需要吗?

评论