Vue 3 响应式陷阱:ref/reactive 的选择、解构丢响应与 shallowRef 优化

test12026-09-1210 次阅读

ref 与 reactive 怎么选

Vue 3 的响应式有两条入口:ref 包任意类型(访问要加 .value),reactive 只包对象且自动深度代理。基本类型用 ref,对象类型两者都能用,但 reactive 在重新赋值时有个大坑。

import { ref, reactive } from 'vue';

const count = ref(0);
count.value++; // ref 必须 .value

const state = reactive({ n: 0 });
state.n++; // reactive 直接点属性

解构会丢响应

这是最常见的问题:从 reactive 对象解构出来的属性,脱离了原对象就不再是响应式的。

const state = reactive({ count: 0, user: { name: 'a' } });

// 错误:count 变成普通数字,后续修改不触发更新
const { count } = state;
count = 1; // 视图不会变

// 正确:用 toRefs 把每个属性转成 ref
const { count: c } = toRefs(state);
c.value = 1; // 视图更新

reactive 重新赋值会断引用

reactive 对象不能用 = 整体替换,否则新对象与原引用脱钩,模板里还是旧的那份。

const list = reactive([1, 2, 3]);
// 错误:list 现在指向新数组,但模板绑定的是旧引用
list = [4, 5, 6];

// 正确做法一:用 ref 包数组,整体替换仍保持响应
const list = ref([1, 2, 3]);
list.value = [4, 5, 6];

// 正确做法二:原地修改
list.length = 0;
list.push(4, 5, 6);

大对象用 shallowRef 省性能

当状态是一个很大的对象或第三方实例(如图表、编辑器),你并不需要对它内部做深度代理,只在替换整体时触发更新即可。shallowRef 只追踪 .value 的替换,不递归代理。

import { shallowRef } from 'vue';

const editor = shallowRef(null);
// 只在赋新值时更新,内部字段变化不会触发
editor.value = createEditor();
editor.value.setOption('theme', 'dark'); // 不会触发视图更新

小结

  • 基本类型一律 ref,访问记得 .value。
  • 对象需要重新整体赋值,优先用 ref 而不是 reactive。
  • 解构 reactive 属性用 toRefs,否则丢响应。
  • 大对象或外部实例用 shallowRef 减少代理开销。
T

test1

文章作者

ref 与 reactive 怎么选 Vue 3 的响应式有两条入口:ref 包任意类型(访问要加 .value),r...

分类
技术
发布时间
2026-09-12
字数
约 1238 字
阅读
10 次