vue响应式系统存在四类边界:对象新增/删除属性需用object.assign或reactive重建;数组索引赋值需用splice等方法;嵌套对象初始为null需显式reactive;props只读应通过$emit修改。

Vue 的响应式系统不是“全知全能”的魔法,它在 JavaScript 语言限制下做了合理取舍。真正的问题往往不是系统失效,而是你碰到了它明确划定的几类边界——知道它们在哪、为什么存在、怎么绕过去,比死磕“为什么没更新”高效得多。
对象新增或删除属性不触发更新
Vue 初始化时只对已存在的属性建立响应式连接。后续直接 obj.newKey = 'value' 或 delete obj.oldKey,Proxy 拦截不到,视图自然不动。
- 推荐做法:用 Object.assign({}, obj, { key: value }) 替换整个对象,语义清晰且兼容性好
- 动态添加单个属性时,Vue 3 中可用 reactive({ ...obj, newKey: value }) 重建代理
- 避免在 setup 中反复替换整个对象,若频繁操作,考虑用 shallowRef + 手动 triggerRef
数组通过索引或 length 修改不响应
直接写 arr[0] = newItem 或 arr.length = 0,跳过了 Vue 重写的原型方法(如 splice、push),因此无法触发依赖更新。
- 替换元素优先用 arr.splice(index, 1, newItem)
- 清空数组用 arr.splice(0) 或 arr.length = 0 后手动调用 triggerRef(配合 shallowRef)
- 若需大量索引赋值,建议先构造新数组再整体赋值:arr = [...arr] 或 arr = newArray
嵌套对象首次访问才代理,初始为 null/undefined 就失效
Vue 是懒递归代理:只有读取到 state.user.profile 这一路径时,才会对 profile 创建 reactive。如果它一开始是 null,后面赋值成对象,也不会自动变成响应式。
- 初始化尽量补全结构:user: { profile: { name: '', avatar: '' } }
- 必须动态挂载时,显式用 reactive({}) 包裹再赋值:state.user.profile = reactive({ name: 'Tom' })
- 对不需要响应式的大型外部对象(如第三方库实例),用 markRaw 避免无谓代理
Props 只读但深层属性可响应,改错地方就静默失败
子组件接收的 props 是只读响应式代理。你可以读 props.user.name 并监听变化,但不能写 props.user = {} 或 props.count++ —— 这些操作既不生效,也不报错。
- 想修改数据?必须通过 $emit 通知父组件,由源头更新
- 需要本地可写副本:用 toRefs(props) 解构后,再用 ref 或 reactive 封装新变量
- 派生状态优先用 computed,而非直接拷贝 props 对象
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










