Vue 中 data () 直接定义与手动 reactive 的区别:为什么有时需要多此一举?

问题描述:

在 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 手动创建响应式。