Vue data 为什么必须是函数
理解 Vue 组件中 data 必须是函数的原因
问题
在 Vue 组件中,为什么 data 必须是一个函数,而不能直接是一个对象?
解答
问题复现
如果 data 是对象,多个组件实例会共享同一份数据:
// 错误示例:data 是对象
const Component = {
template: '<button @click="count++">{{ count }}</button>',
data: {
count: 0
}
}
// 创建两个实例
const vm1 = new Vue({ ...Component })
const vm2 = new Vue({ ...Component })
// vm1 和 vm2 的 data 指向同一个对象
vm1.count++
console.log(vm2.count) // 1,被影响了
正确做法
data 是函数时,每个实例都有独立的数据副本:
// 正确示例:data 是函数
const Component = {
template: '<button @click="count++">{{ count }}</button>',
data() {
return {
count: 0
}
}
}
// 创建两个实例
const vm1 = new Vue({ ...Component })
const vm2 = new Vue({ ...Component })
// 每个实例有独立的 data
vm1.count++
console.log(vm1.count) // 1
console.log(vm2.count) // 0,互不影响
模拟 Vue 的实现
// 简化版实现,展示原理
function VueComponent(options) {
// 如果 data 是函数,调用它获取新对象
this.data = typeof options.data === 'function'
? options.data()
: options.data
}
const options = {
data() {
return { count: 0 }
}
}
const instance1 = new VueComponent(options)
const instance2 = new VueComponent(options)
instance1.data.count = 10
console.log(instance1.data.count) // 10
console.log(instance2.data.count) // 0,独立的数据
根实例的特殊情况
根实例(new Vue())可以用对象,因为它只会被创建一次:
// 根实例可以用对象(但不推荐)
new Vue({
el: '#app',
data: {
message: 'Hello'
}
})
// 推荐统一使用函数形式
new Vue({
el: '#app',
data() {
return {
message: 'Hello'
}
}
})
关键点
- 引用类型共享问题:对象是引用类型,多个实例会共享同一份数据
- 函数返回新对象:每次调用函数都返回一个新对象,保证数据隔离
- 组件复用场景:组件会被多次实例化,必须保证每个实例数据独立
- 根实例例外:根实例只创建一次,可以用对象,但建议统一用函数
- Vue 3 变化:Composition API 中使用
ref/reactive,不再有这个问题
目录