问答题121/1767vue3 中 ref 和 reactive 有什么区别?

难度:
2025-08-04 创建

参考答案:

在 Vue 3 中,refreactive 都用于创建响应式数据,但二者并不是简单的“语法差异”,而是响应式模型设计层面的两种不同抽象

理解它们的区别,需要从数据包装方式、依赖追踪粒度以及使用场景来看。


一、本质区别:响应式包装模型不同

ref —— 对“值”的响应式封装

ref 的核心思想是:把一个值包装成一个带 .value 的响应式容器

1const count = ref(0);

内部结构可以抽象理解为:

1{ 2 value: 0 // getter/setter 被 Proxy 或响应系统追踪 3}

Vue 追踪的是:

1count.value

也就是说,响应性绑定在 .value 上。

它既可以包裹:

  • 基本类型(number、string、boolean)
  • 对象
  • 数组

reactive —— 对“对象结构”的代理

reactive 的核心思想是:直接代理一个对象本身

1const state = reactive({ 2 count: 0 3});

Vue 会通过 Proxy 拦截:

1state.count 的 get / set

依赖追踪粒度是 对象属性级别


二、最关键的设计差异

1. 响应式单位不同

  • ref:以“单值”为响应单位
  • reactive:以“对象属性”为响应单位

例如:

1const r = ref({ a: 1 }); 2const s = reactive({ a: 1 });

更新方式:

1r.value = { a: 2 }; // 整体替换 2s.a = 2; // 属性级修改

2. 是否需要 .value

这是使用体验上的明显区别。

1count.value++ // ref 2state.count++ // reactive

原因在于:

  • ref 是容器对象
  • reactive 本身就是代理对象

不过在模板中 Vue 会自动解包 ref:

1{{ count }} <!-- 自动访问 .value -->

3. 对解构的影响不同

这是实际开发中非常重要的一点。

reactive 解构会丢失响应性

1const state = reactive({ count: 0 }); 2const { count } = state; // 非响应式

因为解构得到的是普通值。

需要:

1toRefs(state);

ref 不存在这个问题

1const count = ref(0);

变量本身就是响应式引用。


4. 替换能力不同(非常关键)

reactive 不能安全整体替换:

1state = { count: 1 }; // 响应性丢失

因为 Proxy 已绑定旧对象。

ref 天然支持整体替换:

1stateRef.value = newState;

这也是为什么在很多 store 设计中优先使用 ref。


三、依赖收集粒度差异

Vue 3 的更新是基于访问路径追踪的:

  • reactivetarget + key
  • ref → 单一 dep

因此:

  • reactive 更适合复杂结构
  • ref 更适合频繁整体替换的数据

四、工程实践中的选择原则

通常不是二选一,而是组合使用:

  • 基础类型状态 → ref
  • 局部对象状态 → reactive
  • 可整体替换的数据源 → ref
  • 表单或结构化状态 → reactive

很多状态管理库(如 Pinia)内部实际上大量使用 ref 来避免对象替换问题。


五、为什么 Vue 3 同时保留两套 API

Vue 2 的响应式基于 Object.defineProperty,只能处理对象属性。

Vue 3 引入 Proxy 后,本可以统一模型,但仍保留 ref,原因是:

  1. JavaScript 基本类型无法被 Proxy
  2. 需要显式的“引用语义”
  3. 提供更可控的依赖粒度
  4. 支持函数式组合(Composition API)

本质上:

ref 提供值语义(value semantics),reactive 提供对象语义(object semantics)。

最近更新时间:2026-02-24

赞赏支持

题库维护不易,您的支持就是我们最大的动力!