响应式链断裂主因是解构props或替换reactive对象;应通过props访问、用torefs保持响应式,只改属性不换对象,慎用shallowref,需主动响应时用watch。

因为 reactive 创建的对象本身是响应式的,但传给子组件后,如果在子组件里直接解构 props,或父组件错误地替换了整个 reactive 对象,响应式链就断了——不是数据“不动了”,而是 Vue 已经收不到变化通知了。
别直接解构 props
在 setup() 中写 const { count } = props,得到的是一个普通数字或字符串,不是响应式引用。count 只是那一刻的快照值,后续父组件改了 props.count,它不会变。
正确做法是始终通过 props.count 访问,或用 toRefs(props) 转换:
- 用
toRefs(props):它会把 props 里每个字段转成 ref,保持响应式 - 模板中直接写
{{ props.count }},不经过解构 - 需要计算时,用
computed(() => props.count * 2),依赖依然能追踪
父组件别替换 reactive 整体引用
reactive 的响应式只作用于对象内部属性(比如 state.count = 100),不监听变量本身的赋值操作。如果父组件写了 state = { count: 200 },等于扔掉了原来的代理对象,子组件还拿着旧的引用,自然没反应。
应该只改属性,不要换对象:
- ✅ 正确:
state.count = 200或Object.assign(state, { count: 200 }) - ❌ 错误:
state = reactive({ count: 200 })或state = { count: 200 } - 如果真要全量更新,用
Object.assign(state, newData),保留原响应式代理
注意 shallowRef 和普通 ref 的区别
如果父组件用 shallowRef 包了一个数组或对象,只对 .value 层级做响应式,内部属性修改(比如 push、赋值)不会触发更新。
常见表现:列表渲染不出来、filter 后视图不刷新。
- 要么换成
ref(自动深层响应) - 要么手动调用
triggerRef(shallowRefVar)强制通知 - 或者先拼好新数组,再整体赋值给
shallowRefVar.value = newArray
子组件想主动响应 prop 变化?用 watch 或 onUpdated
有些逻辑不能只靠模板渲染,比如收到新数据要发请求、重置表单、滚动到顶部等。
- 用
watch(() => props.info, (newVal) => { /* 处理新值 */ }) - 避免在 setup 顶层直接读 props 赋值给 ref,那只会取一次初始值
- 不需要同步状态时,别把 props 再存一遍到子组件的 ref 或 reactive 里











