Vue 中的 ref 与 reactive

在 Vue 3 的组合式 API 中,refreactive 是创建响应式数据的两种主要方式。它们都用于使数据具有响应性,但在使用场景和特性上存在重要区别。

核心区别概览

特性 ref reactive
数据类型 所有类型(原始值/对象) 仅对象类型(Object/Array/Map/Set)
访问方式 需要 .value(脚本中) 直接访问属性
模板中使用 自动解包(无需 .value 直接访问属性
重新赋值 支持(ref.value = newValue 不支持(会失去响应性)
解包行为 在 reactive 中自动解包 不适用
TypeScript 支持 更简单 需要更复杂的类型定义

深入解析 ref

基本用法

javascript 复制代码
import { ref } from 'vue';

// 创建 ref
const count = ref(0);
const user = ref({ name: 'John', age: 30 });

// 访问值(脚本中)
console.log(count.value); // 0
console.log(user.value.name); // 'John'

// 修改值
count.value = 1;
user.value.age = 31;

主要特性

  1. 支持所有数据类型:可以包装原始值(数字、字符串、布尔值)和对象

  2. .value 访问 :在 JavaScript 代码中需要通过 .value 访问和修改

  3. 模板自动解包 :在模板中直接使用变量名,无需 .value

    html 复制代码
    <template>
      <div>{{ count }}</div> <!-- 直接使用 count,而非 count.value -->
    </template>
  4. 可重新赋值 :可以完全替换值而不丢失响应性

    javascript 复制代码
    user.value = { name: 'Alice', age: 25 }; // 有效

适用场景

  • 原始值(数字、字符串、布尔值)

  • 需要重新赋值的对象

  • 从组合函数返回响应式数据

  • 模板引用(DOM 元素引用)

    html 复制代码
    <input ref="inputRef">

深入解析 reactive

基本用法

javascript 复制代码
import { reactive } from 'vue';

// 创建 reactive 对象
const state = reactive({
  count: 0,
  user: {
    name: 'John',
    address: {
      city: 'New York'
    }
  }
});

// 访问和修改
console.log(state.count); // 0
state.count = 1;

// 深层嵌套访问
console.log(state.user.address.city); // 'New York'
state.user.address.city = 'Los Angeles';

主要特性

  1. 仅限对象类型:只能用于对象、数组、Map、Set 等

  2. 深层响应性:嵌套对象自动转换为响应式

  3. 直接访问属性 :不需要 .value 语法

  4. 不能重新赋值 :重新赋值整个对象会破坏响应性

    javascript 复制代码
    // 错误用法 - 会失去响应性
    state = { count: 10 }; 
    
    // 正确用法 - 修改属性
    state.count = 10;
  5. 自动解包 ref :当 ref 作为 reactive 对象的属性时,会自动解包

    javascript 复制代码
    const count = ref(0);
    const state = reactive({ count });
    
    console.log(state.count); // 0 - 不需要 .value
    state.count = 1; // 相当于 count.value = 1

适用场景

  • 复杂的嵌套对象
  • 不需要重新赋值的状态对象
  • 表单对象
  • 需要深层响应的数据结构

关键区别详解

1. 数据类型支持

  • ref:可以包装任何值类型(原始值、对象、数组等)
  • reactive:只能处理对象类型(Object、Array、Map、Set)

2. 访问方式

javascript 复制代码
// ref 需要 .value
const num = ref(0);
num.value = 1;

// reactive 直接访问
const obj = reactive({ num: 0 });
obj.num = 1;

3. 重新赋值能力

javascript 复制代码
// ref 可以重新赋值
const data = ref({ count: 0 });
data.value = { count: 1 }; // 有效,保持响应性

// reactive 不能重新赋值
const state = reactive({ count: 0 });
state = { count: 1 }; // 无效,会破坏响应性

4. 在模板中的使用

两者在模板中都可以直接访问:

html 复制代码
<!-- ref -->
<div>{{ count }}</div> 

<!-- reactive -->
<div>{{ state.count }}</div>

5. 解包行为

javascript 复制代码
const count = ref(0);

// 在 reactive 中自动解包
const state = reactive({ count });
console.log(state.count); // 0 - 自动解包

// 在数组或集合中不会自动解包
const arr = reactive([count]);
console.log(arr[0].value); // 需要 .value

最佳实践与使用建议

  1. 优先使用 ref 的情况

    • 处理原始值(数字、字符串等)
    • 需要重新赋值的变量
    • 从组合函数返回响应式数据
    • 简单的响应式状态
  2. 优先使用 reactive 的情况

    • 复杂的嵌套对象状态
    • 不需要重新赋值的状态容器
    • 表单处理对象
    • 当需要深层响应性时
  3. 混合使用模式

    javascript 复制代码
    import { ref, reactive } from 'vue';
    
    export function useUser() {
      const loading = ref(false);
      const error = ref(null);
      
      const user = reactive({
        name: '',
        email: '',
        preferences: {
          theme: 'light',
          notifications: true
        }
      });
      
      async function fetchUser(id) {
        loading.value = true;
        try {
          const response = await fetch(`/api/users/${id}`);
          const data = await response.json();
          Object.assign(user, data); // 正确更新 reactive 对象
        } catch (err) {
          error.value = err.message;
        } finally {
          loading.value = false;
        }
      }
      
      return {
        loading,
        error,
        user,
        fetchUser
      };
    }
  4. 解构注意事项

    • 直接解构 reactive 对象会失去响应性:

      javascript 复制代码
      const state = reactive({ count: 0 });
      
      // 错误 - 失去响应性
      const { count } = state;
    • 使用 toRefs 保持响应性:

      javascript 复制代码
      import { toRefs } from 'vue';
      
      const state = reactive({ count: 0 });
      const { count } = toRefs(state); // 保持响应性

性能考虑

  • ref:对于原始值有轻微性能开销(需要包装对象)
  • reactive:处理大型对象时有更好的性能
  • 实际应用中性能差异通常可以忽略不计
  • 避免过度使用响应式系统,只在需要时使用

总结

场景 推荐使用
原始值(数字、字符串等) ref
需要重新赋值的对象 ref
组合函数返回值 ref
模板引用(DOM 元素) ref
复杂嵌套对象 reactive
不需要重新赋值的状态容器 reactive
表单处理对象 reactive

在 Vue 3 开发中,理解 refreactive 的区别至关重要。大多数情况下,我会推荐:

  • 优先使用 ref:因其更简单直观,适用于大多数场景
  • 在需要时使用 reactive:处理复杂嵌套对象时更优雅

两者不是互斥的,而是互补的。在实际项目中,经常混合使用它们,利用各自的优势创建更清晰、更易维护的代码结构。

相关推荐
崔庆才丨静觅22 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax