Vue 3 响应式最常见的困惑,不是“Proxy 原理是什么”,而是三件更实际的事:
- 一个普通值为什么要包进
ref - 一个对象为什么有时用
reactive - 为什么对象一解构就“没反应了”
如果先把这三个问题理顺,ref、reactive、toRefs 的选择就会清楚很多。
什么是响应式
在 Vue 3 中,响应式 是指 Vue 对数据进行“代理”,使得数据的变化能够被追踪,并且当数据变化时,相关的视图部分会自动更新。Vue 使用现代的 JavaScript Proxy API 来实现这一点,能够拦截对象属性的读取和修改。
基本类型和引用类型为什么影响写法
基本类型
基本类型包括:String、Number、Boolean、Null、Undefined 和 Symbol。这些数据类型的特点是 值传递。当将一个基本类型的变量赋值给另一个变量时,新的变量会持有该值的副本。修改副本不会影响原始值。
let num1 = 10;
let num2 = num1; // num2 是 num1 的副本
num2 = 20; // 修改 num2 不会影响 num1
console.log(num1); // 输出 10
在 Vue 3 里,基本类型通常用 ref 包起来,因为 Vue 需要一个可以被追踪的壳:
import { ref } from 'vue';
const count = ref(0);
count.value = 1; // 修改基本类型变量
引用类型
引用类型包括:Object、Array、Function、Date、RegExp 等。这些数据类型的特点是 引用传递。当将一个引用类型的变量赋值给另一个变量时,两个变量指向同一内存地址,因此修改其中一个变量的属性或内容会直接影响到另一个变量。
let obj1 = { name: 'Vue3' };
let obj2 = obj1; // obj2 和 obj1 引用同一个对象
obj2.name = 'Vue 3'; // 修改 obj2 会影响 obj1
console.log(obj1.name); // 输出 'Vue 3'
对象更适合 reactive,因为它能直接把对象代理成可追踪结构:
import { reactive } from 'vue';
const state = reactive({ count: 0, name: 'Vue3' });
state.count = 1; // 修改对象的属性,视图会自动更新
ref 和 reactive 到底怎么选
1. 响应式深度
- 基本类型 的响应式是简单的,直接对值本身进行追踪和更新。你可以使用
ref来处理基本类型数据。 - 引用类型 的响应式会递归地处理对象内部的属性,使得对象的每个属性都能被 Vue 的响应式系统追踪。这意味着修改嵌套对象的属性也能触发视图的更新。
const state = reactive({ user: { name: 'Vue3' } });
state.user.name = 'Vue 3'; // 修改嵌套属性,视图会自动更新
对于引用类型的嵌套结构,Vue 会深度地追踪每个属性,确保嵌套对象的属性变化能被捕捉到并更新视图。
2. 解构为什么会丢响应性
-
基本类型的 ref:你拿的是一个 ref 包装对象,本身没有“把内部值拆成普通变量后仍自动响应”这回事。
const count = ref(0); const { value } = count; // 解构出来的 value 依然是响应式的 -
reactive 对象的解构:直接解构后,变量通常不再保持响应式绑定,除非使用
toRefs或toRef。const state = reactive({ count: 0, name: 'Vue3' }); const { count, name } = state; // count 和 name 不是响应式的 // 使用 toRefs 保持解构后的变量响应式 const { count, name } = toRefs(state); // count 和 name 都是响应式的
3. 经验法则
- 单个值、布尔开关、计数器:
ref - 表单对象、组件状态对象:
reactive - 要把
reactive对象拆出去给模板或组合式函数:toRefs
toRefs 到底解决什么
toRefs 不是“让一切都变高级”,它只是把 reactive 对象的每个属性,转换成仍然和原对象保持连接的 ref:
const state = reactive({ count: 0, name: 'Vue3' });
const { count, name } = toRefs(state);
这在组合式 API 里特别常见,因为你经常需要把状态拆给不同函数或模板使用。
常见误区
- 用
reactive包一个单独数字,然后到处怀疑为什么不顺手。 - 直接解构
reactive后,又以为 Vue “失去响应性”。 - 为了统一写法,把所有东西都包成
ref,结果对象访问全是.value.xxx。
总结
- 单值优先
ref,对象优先reactive。 - 直接解构
reactive容易丢掉响应性,用toRefs保持绑定。 - 选择 API 的关键不是背定义,而是看数据结构和后续使用方式。
如果你也在比较 React 的状态与副作用边界,可以顺着看 理解与掌控副作用:Vue 3 和 React;如果你在处理对象拷贝和值引用差异,也可以看 JavaScript 对象复制指南。
继续阅读
Next.js Image 指南:sizes、fill 和远程图片
基于当前 Next.js Image 官方文档,解释 width/height、fill、sizes、preload、placeholder、remotePatterns 的作用,以及哪些旧教程里的 layout、objectFit 写法已经不该继续照搬。
18 分钟理解与掌控副作用:前端开发(Vue 3 和 React)中的关键环节
在现代前端开发中,副作用(Side Effects)是一个经常被提到的概念。它指的是那些在执行计算或操作时,不仅影响当前函数的输出,还可能对外部世界产生某些影响的操作。常见的副作用包括:数据请求、事件监听、定时器、DOM 操作等。处理副作用是前端开发中非常重要的一部分,尤其是在构
13 分钟深入理解 DOM 和 CSSOM:网页渲染的核心
DOM 是浏览器用于表示网页内容和结构的对象模型。它将网页的 HTML 或 XML 文档表示为一个树形结构,每个部分(如元素、文本和属性)都成为一个节点。通过 JavaScript,开发者可以操作这些节点,从而动态地修改页面的内容和结构。CSSOM 是浏览器用来表示 CSS 样式
订阅 FreeMac
每周精选:免费 Mac 软件评测、可信来源更新、替代方案和少折腾指南。