What Causes This Warning?
This warning occurs in the Options API when the data option is not a function that returns an object, or when the function returns something other than a plain object (like undefined, null, or an array).
The Problem
// ❌ data as object (not a function)
export default {
data: {
count: 0
}
}
// ❌ data function returning nothing
export default {
data() {
const count = 0
// No return statement!
}
}
// ❌ data function returning array
export default {
data() {
return [1, 2, 3]
}
}
// ❌ data function returning null
export default {
data() {
return null
}
}
The Fix
Return a Plain Object
// ✅ data as function returning object
export default {
data() {
return {
count: 0,
message: 'Hello',
items: []
}
}
}
With Composition API
<script setup>
import { ref, reactive } from 'vue'
// ✅ Use ref for primitives
const count = ref(0)
const message = ref('Hello')
// ✅ Use reactive for objects
const state = reactive({
items: [],
loading: false
})
</script>
Common Scenarios
Forgetting Return Statement
// ❌ Missing return
export default {
data() {
const state = {
count: 0
}
// Forgot to return!
}
}
// ✅ With return
export default {
data() {
return {
count: 0
}
}
}
Conditional Return
// ❌ Conditional might return undefined
export default {
data() {
if (someCondition) {
return { count: 0 }
}
// Returns undefined if condition is false
}
}
// ✅ Always return an object
export default {
data() {
if (someCondition) {
return { count: 0, extra: true }
}
return { count: 0 }
}
}
Arrow Function with Object Literal
// ❌ Arrow function needs parentheses for object literal
export default {
data: () => { count: 0 } // This is a block, not an object!
}
// ✅ Wrap object in parentheses
export default {
data: () => ({ count: 0 })
}
// ✅ Or use regular function
export default {
data() {
return { count: 0 }
}
}
Async Data Initialization
// ❌ data cannot be async
export default {
async data() {
const result = await fetchData()
return { result }
}
}
// ✅ Initialize empty, fetch in lifecycle
export default {
data() {
return {
result: null,
loading: true
}
},
async created() {
this.result = await fetchData()
this.loading = false
}
}
Class Instance in Data
// ❌ Class instances can cause issues
export default {
data() {
return new MyDataClass() // Not a plain object
}
}
// ✅ Return plain object with class instance as property
export default {
data() {
return {
myClass: new MyDataClass()
}
}
}
Why data Must Be a Function
In Vue, data must be a function so each component instance gets its own reactive data object:
// ❌ Shared data object (causes bugs)
const sharedData = { count: 0 }
export default {
data: sharedData // All instances share same object!
}
// ✅ Factory function (each instance gets fresh object)
export default {
data() {
return { count: 0 } // New object for each instance
}
}
Migrating to Composition API
// Options API
export default {
data() {
return {
count: 0,
user: { name: '' },
items: []
}
}
}
// Composition API equivalent
import { ref, reactive } from 'vue'
export default {
setup() {
const count = ref(0)
const user = reactive({ name: '' })
const items = ref([])
return { count, user, items }
}
}
// Script setup (cleanest)
<script setup>
import { ref, reactive } from 'vue'
const count = ref(0)
const user = reactive({ name: '' })
const items = ref([])
</script>
Quick Checklist
-
datamust be a function, not an object - Function must return a plain object
{} - Don’t forget the
returnstatement - Wrap arrow function object literals in parentheses
- Don’t return arrays, null, or undefined
- Use lifecycle hooks for async initialization
- Consider migrating to Composition API