vue 3 的 reactive 中可存放函数或类实例,但它们本身不响应式,修改其内部状态不会触发视图更新;需通过 ref/reactive 管理状态或用 shallowref/markraw 安全持有。

在 Vue 3 的 reactive 中,**可以存放函数或类实例,但需注意:它们本身不会被转为响应式,也不会触发依赖追踪**。也就是说,函数和类实例作为属性值存入 reactive 对象后,能正常调用、访问,但修改其内部状态(比如类的私有属性)或重赋值该属性时,**不会引起视图更新**,除非这些操作显式改变了 reactive 对象中被 Vue 追踪的响应式字段。
函数可以放进 reactive,但不响应变化
你可以把普通函数、箭头函数甚至方法直接赋给 reactive 对象的属性:
import { reactive } from 'vue'
<p>const state = reactive({
count: 0,
// ✅ 合法:函数作为属性值
increment() {
this.count++
},
reset: () => {
state.count = 0
},
handler: function (e) {
console.log(e)
}
})
</p>这些函数能正常使用,但要注意:
- 函数体内部的
this指向 reactive 代理对象(仅限普通函数写法,箭头函数无this) - 函数本身不是响应式——你不能监听“这个函数被替换了”这件事
- 函数内部若只读取或修改
state.count等响应式字段,才会触发更新;若修改的是非响应式对象(如普通 class 实例的属性),则不会
类实例可以放进去,但内部状态不自动响应
例如定义一个简单的计数器类:
class Counter {
constructor(initial = 0) {
this.value = initial // ❌ 普通属性,非响应式
}
inc() {
this.value++
}
}
<p>const state = reactive({
counter: new Counter(5),
count: ref(0) // ✅ 响应式字段
})
</p>此时 state.counter.inc() 能执行,state.counter.value 也能读取,但:
-
state.counter.value的变化不会通知 Vue,模板中绑定它不会更新 - 如果希望类的状态可响应,需让类内部使用
ref或reactive管理自身状态,或改用 Composition API 封装逻辑
更推荐的做法:函数放 setup 或用 method,类状态外置
为保持响应式语义清晰,建议:
- 事件处理器、工具函数尽量定义在
setup()内部或独立模块,通过return暴露给模板(无需塞进 reactive) - 若需在 reactive 对象中组织行为,可用
computed或watch配合ref控制副作用 - 对类实例,优先将其状态抽离为
reactive或ref,类本身只负责逻辑,不承载响应式数据
特殊情况:需要响应式类?考虑 shallowRef 或 markRaw
如果你必须把整个类实例当作一个不可代理(避免 Proxy 干预)但又想保留其引用的值,可用:
-
shallowRef:包装类实例,不深层代理,但.value变化可被侦听 -
markRaw:标记类实例为“非响应式”,防止被 reactive 递归代理(避免警告或意外行为)
import { shallowRef, markRaw } from 'vue'
<p>class ApiClient {
constructor(url) {
this.url = url
}
fetch() { /<em> ... </em>/ }
}</p><p>// ✅ 安全持有类实例,且 .value 更改可被 watch
const client = shallowRef(null)
client.value = markRaw(new ApiClient('/api'))</p><p>// ✅ 在 reactive 中安全存放(避免 proxy 报错)
const state = reactive({
api: markRaw(new ApiClient('/api'))
})
</p>前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










