问题描述:
在 Vue 开发中,我们常看到两种定义响应式数据的方式:
一种是直接在 data() 中返回数据,比如:
data() {
return {
orders: orderScriptData.orders,
loading: {},
isModalShow: false,
currentOrder: {},
reviewLoading: false
}
}
另一种则是先通过 Vue.reactive 手动创建响应式对象,再在 data() 中返回,例如:
// 先手动创建响应式对象
const state = Vue.reactive({ count: 0 })
// 再在 data 中返回
data() {
return { state }
}
这两种写法都能实现数据响应式,为什么会存在第二种看似 “多此一举” 的方式?直接在 data() 里定义数据不更简单吗?
Vue.reactive使用场景
数据需要在组件外部定义(非 data() 内部)
如果你的响应式数据不是在组件的 data() 里定义,而是在组件外部(比如全局状态、工具函数中),这时候 Vue 不会自动处理,必须手动用 Vue.reactive 标记,否则数据修改不会触发视图更新。
例如,你想在多个组件间共享一个全局计数器:
<!-- 全局响应式数据(在所有组件外部) -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
// 这里不在任何组件的 data() 里,必须手动用 reactive
const globalState = Vue.reactive({ count: 0 })
// 组件 A
const ComponentA = {
template: `<p>A组件: {{ globalState.count }}</p>`,
data() {
return { globalState } // 仅暴露给模板使用,数据本身已在外部用 reactive 处理
}
}
// 组件 B
const ComponentB = {
template: `<button @click="add">B组件加1</button>`,
methods: {
add() {
globalState.count++ // 修改全局响应式数据,A、B组件视图都会更新
}
}
}
// 根组件
Vue.createApp({
components: { ComponentA, ComponentB }
}).mount('#app')
</script>
这里的 globalState 是在组件外部定义的,必须用 Vue.reactive 手动标记为响应式,否则修改 count 时,组件视图不会更新。
需要更细粒度的响应式控制
在 data() 里定义的对象,Vue 会对整个对象做响应式处理。但如果某些数据不需要被组件的 data() 管理(比如临时数据、非组件相关的工具数据),可以用 Vue.reactive 单独创建,避免混入组件的 data 中导致逻辑混乱。
例如,组件内部有一个 “临时筛选条件”,不想和 data 里的业务数据混在一起:
// 组件内部
export default {
data() {
return {
orders: [] // 业务数据,由 data 管理
}
},
created() {
// 临时筛选条件,单独用 reactive 管理,不和业务数据混在 data 里
this.filterState = Vue.reactive({
keyword: '',
status: 'all'
})
}
}
以上,组件内部的数据,直接写在 data() 里最方便;组件外部的数据,需要用 Vue.reactive 手动创建响应式。