人人都会AI编程

直接替换 reactive 对象、解构丢失响应式

更新时间:2026-07-09

响应式系统的核心是 Vue 对数据的代理。一旦你绕过了这层代理,响应式就会失效。下面两个场景是实际开发中最常见的坑,理解它们能避免大量“为什么界面不更新”的困扰。

直接替换 reactive 对象的整体引用

问题代码:

import { reactive } from 'vue'

const state = reactive({ count: 0, name: 'Alice' })

// ❌ 错误:直接覆盖整个对象
state = { count: 1, name: 'Bob' }   // 这句会报错或失效,state 不再是响应式对象

为什么失效?
reactive() 返回的是一个 Proxy 代理对象,你把这个代理赋值给了变量 state。当你用 state = ... 覆盖整个对象时,你实际上是丢掉了这个代理,让 state 重新指向了一个普通对象。这个新对象没有经过 Proxy 包裹,自然失去响应式。而且,由于你修改的是变量 state 自身的引用,原代理对象还在但已无法访问,视图不会更新。

正确做法:

  1. 修改对象的属性,而不是替换整个对象
   const state = reactive({ count: 0, name: 'Alice' })
   // ✅ 正确:修改属性
   state.count = 1
   state.name = 'Bob'
   
  1. 如果确实需要整体替换数据,使用 ref

ref 可以包裹任意类型(包括对象),通过 .value 替换时,Vue 会重新创建响应式连接。

   import { ref } from 'vue'
   const state = ref({ count: 0, name: 'Alice' })
   state.value = { count: 1, name: 'Bob' }   // ✅ 正确,响应式保持
   
  1. 使用 Object.assign 合并新值(保持同一代理引用)
   const state = reactive({ count: 0, name: 'Alice' })
   Object.assign(state, { count: 1, name: 'Bob' })  // ✅ 属性更新,响应式保留
   

解构丢失响应式

问题代码:

import { reactive } from 'vue'

const state = reactive({ count: 0, name: 'Alice' })

// ❌ 错误:解构后得到普通值,失去响应式连接
let { count, name } = state
count++          // 视图不更新
name = 'Bob'     // 视图不更新

为什么失效?
当你从 reactive 对象中解构属性时,你取得的是属性的当前值。对于基本类型(如 count),它就是一个纯数字,没有和原来的 Proxy 对象建立任何联系。之后你修改这个局部变量,Vue 完全感知不到。

正确做法:

  1. 使用 toRefs 将解构后的值转为 Ref,保持响应式连接
   import { reactive, toRefs } from 'vue'
   const state = reactive({ count: 0, name: 'Alice' })
   const { count, name } = toRefs(state)
   count.value++   // ✅ 视图更新
   name.value = 'Bob'  // ✅ 视图更新
   

解构出的 countname 变成了 Ref,它们与原始 state 对象共享响应式,修改 .value 会同步更新源对象。

  1. 不解构,直接使用 state.countstate.name

这是最稳妥的方式,在模板中尤其自然:

   <template>
     <p>{{ state.count }} - {{ state.name }}</p>
   </template>
   

<script setup> 中,也可以直接使用 state.count,不需要解构。

  1. 对于 ref 包裹的对象,用 .value 访问属性,不直接解构
   const state = ref({ count: 0, name: 'Alice' })
   // ✅ 通过 state.value 访问属性
   state.value.count++
   // 若用解构同样需要 toRefs
   const { count, name } = toRefs(state.value)
   

一句话总结:响应式依赖代理引用,不要切断这层联系。修改对象用属性赋值,整体替换用 ref,解构时用 toRefs 保持连接。