Vue 2, why data must be a function
By Flavio Copes
Using Vue you might surely asked yourself the question 'why must data be a function that returns an object, and not just an object?'
In Vue 2 components, data must be a function because components are reused. If data were a plain object, every instance of the component would share the same state. A function returns a fresh object for each instance.
Using Vue you might surely asked yourself the question “why must data be a function that returns an object, and not just an object?”
<template>
<a v-on:click="counter = counter + 1">{{counter}}</a>
</template>
<script>
export default {
data: function() {
return {
counter: 0
}
}
}
</script>
Especially considering that in some places, data is not a function, as you most probably see in the App component in several examples.
What happens with a plain object
The explanation is that when the component is used multiple times, if it’s not a function, but a regular object, like this:
data: {
counter: 0
}
then because of how JavaScript works, every single instance of the component will share this property.
Objects in JavaScript are passed by reference. The component definition is created once, so that data object exists once. Every instance Vue creates from the definition points to the same object in memory.
You can see the problem with plain JavaScript:
const shared = { counter: 0 }
const first = shared
const second = shared
first.counter++
second.counter //1
first and second look independent, but they reference the same object. Change one, and the other changes too.
Now picture that counter component used three times on a page. Click one counter, and all three go up together. Not what you want.
The fix
This is not what you want in 99.9% of the cases, and instead you must do:
data: function() {
return {
counter: 0
}
}
Every time Vue creates a new instance of the component, it calls this function and gets a brand new object. No sharing.
You’ll often see the shorter method syntax, which does the same thing:
data() {
return {
counter: 0
}
}
Why does the root instance get away with it?
The exception you see in examples is the root instance, created with new Vue({ ... }). There, data can be a plain object.
The reason: the root instance is created once and never reused, so there’s nothing to share the object with.
Components, on the other hand, are definitions meant to be instantiated many times. That’s why Vue enforces the function there, and warns you in the console if you use a plain object.
It might be non-intuitive at first, but once you accept this explanation and learn that it’s kind of harmful to your application, and a possible source of bugs, you’ll remember to always use a function for data.