I am reading up on Vue components, and find their explanation of why data needs to be a function somewhat confusing:
The root instance
The data option should always be a function in the context of components which returns a fresh object.
This precaution is made by vue. So whenever you define the object directly in the data option, vue will catch for making the mistake.
Components are never allowed to directly mutate its state. This prevents us from messing up and doing bad things where components do not have their own state.
If this precaution is not made by vue, then you will have a chance to mutate any other components that owns from the component and this would be a security issue.
Example from the documentation:
It’s good to understand why the rules exist though, so let’s cheat.
<div id="example-2">
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
var data = { counter: 0 }
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// data is technically a function, so Vue won't
// complain, but we return the same object
// reference for each component instance
data: function () {
return data
}
})
new Vue({
el: '#example-2'
})
Since all three component instances share the same data object, incrementing one counter increments them all! Ouch. Let’s fix this by instead returning a fresh data object:
data: function () {
return {
counter: 0
}
}
Now all our counters each have their own internal state.
Because when Vue init data,
function initData(vm){
let data = vm.$options.data
data = vm._data = typeof data === ‘function’ ? getData(data, vm) : data || {}
/*
Because here,data is a reference from vm.$options.data,
if data is an object,
when there are many instances of this Component,
they all use the same `data`
if data is a function, Vue will use method getData( a wrapper to executing data function, adds some error handling)
and return a new object, this object just belongs to current vm you are initializing
*/
……
// observing data
observe(data, true)
}
From my understanding of this, It's to save memory
Many frameworks, such as Angular 2 or, (at times) React, make each instance of a component a separate object. This means that everything each component needs is initialized for every component. Normally though, you really only need to keep a component’s data separate for each initialization. Methods and such stay the same.
Vue avoids that pitfall by having data be a function that returns an object. That allows separate components to have separate internal state without needing to fully re-instantiate the entire component. Methods, computed property definitions, and lifecycle hooks are created and stored only once, and run against every instance of a component.
See this
It must be a function because otherwhise the data will be shared among all instances of the component, as objects are call by reference rather than call by value. This does not only happen when you reference a global object but also when data is an object itself. If data is a factory-function that returns an object this object will be created from scratch every time you mount a new instance of the component instead of just passing a reference to the global data.