Vue3 中有哪些常见会导致"响应式失效"的坑点

Vue 3 中常见导致"响应式失效"的坑点总结 🔥

🧠 1. 直接整体替换 reactive 对象

let obj = reactive({ a: 1 });

obj = { a: 2 };  // ❌ 失去响应式
  • 原因:代理的是旧对象,新对象是普通对象。
  • 正确做法:用 Object.assign(obj, { a: 2 })

🧠 2. ref 里面存的是对象,还直接改引用

const objRef = ref({ a: 1 });

objRef.value = { a: 2 }; // ✅ 这种是可以的(ref的重新赋值是可以响应的)

BUT!⚡ 这里有细节:

  • ref 会劫持 .value
  • 但是如果内部对象变化而不改引用,需要手动处理深层响应式(比如 objRef.value.a = 2 没问题)
  • 所以操作对象要小心区分是浅层还是深层!

🧠 3. 数组直接赋新数组引用

const arr = reactive([1, 2, 3]);

arr = [4, 5, 6];  // ❌ 失效
  • 原因:跟对象一样,换引用就失效。
  • 正确做法:直接操作原数组,比如:
    arr.splice(0, arr.length, 4, 5, 6);
    

🧠 4. 使用了不是响应式的 API 修改数据

比如你直接用 Object.defineProperty 修改了对象属性,那 Vue 是感知不到的。
(Vue 内部自己用的是 Proxy

或者你改了原型链、手动增删属性(没用 Vue.set 之类的老API),也会导致失效。

不过在 Vue 3,对象新增属性这种情况已经自动支持了(Proxy能劫持新增/删除属性)。

但要注意:

  • Map / Set / WeakMap / WeakSet 的操作,有些不是100%响应式,细节复杂。

🧠 5. 使用 shallowReactive / shallowRef 时搞错了深浅

const obj = shallowReactive({
  nested: { a: 1 }
});

obj.nested.a = 2;  // ❌ 这里nested.a修改不会触发响应
  • 原因shallowReactive 只劫持第一层,不递归!
  • 正确做法:要深层次追踪变化,应该用 reactive,不是 shallowReactive

🧠 6. 解构导致丢失响应式

超级常见的误区!

const user = reactive({ name: '张三', age: 18 });

// 解构
const { name, age } = user;

console.log(name); // name 不是响应式的了 ❌
  • 原因:解构的是值,失去了 Proxy 的代理。
  • 正确做法
    • 直接用 user.name
    • 或者用 toRefs(user) 包一层(官方推荐)
import { toRefs } from 'vue';

const { name, age } = toRefs(user); // 这样就保持响应了 ✅

🧠 7. 模板中 v-for 遍历 key 写错,导致更新异常

<div v-for="item in list" :key="index">...</div>  <!-- ❌ 错误写法 -->
  • 正确的 key 应该是独一无二且稳定的值,比如 item.id。
  • 用 index 作为 key,元素顺序变化时,Vue patch 机制就无法正确复用/更新,会引起渲染异常。

🧠 8. watch 深层监听写错

watch(obj, (newVal, oldVal) => {
  // 只会监听 obj 本身,不监听内部属性变化 ❌
});

如果你想监听对象内部变化,需要加 deep: true

watch(obj, (newVal, oldVal) => {
  // 能捕捉到深层变化 ✅
}, { deep: true });
posted @ 2025-04-27 16:26  闲云-野鹤  阅读(433)  评论(0)    收藏  举报