How changes are tracked in Vue
When an object is passed as the data
option to a Vue instance, Vue walks through every property in that object swapping them with getters/setters using Object.defineProperty
.
Vue does not allow adding new root-level properties to the data object after the initialization of a component. This is because Vue modifies every property in the data object on initialization so when the properties change, Vue is notified of the changes.
If there’s a template element referencing b
, there will be an error in the console:
Property or method "b" is not defined on the instance but referenced during render Make sure to declare reactive data properties in the data option.
This is Vue letting you know that b
was never added to the component instance.
A clever workaround would be to initialize b
but set its value to undefined
since the value will be assigned based on some operation later on.
How to create new reactive properties
Since Vue does not allow creating new root-level elements, there are ways to create your own reactive properties after Vue has been initialized which we’ll be looking at now
Using Vue.set()
In order for this to work, the reactive property being created has to be set on an existing property on the data
option in Vue. This should be an object, so what you’ll be doing, in essence, is adding a new property on a nested object. Do not try to add the property directly, that still won’t work.
Using Vue.set()
, you’re letting Vue know that you’re creating another property and it’ll track that property now. The syntax for doing that is: Vue.set(object_name, new_property, new_value)
. To use the .set()
method inside a component instance, use .$set()
, it is an alias for Vue.set()
, so the syntax will look like this:
Using Object.assign()
You can use Object.assign()
if you’ll be adding more than one property on the existing object.
The reason we created a new object with new properties and old ones is so Vue will run through all properties now and make them reactive. If we only added new properties to the object, Vue would not be aware.
It’s also possible to do that in a component instance too, by doing it this way:
The techniques listed above are the solutions to the known caveat for reactivity in objects, there are also known caveats when dealing with arrays which we’ll be looking at next.
Adding reactive elements to arrays
For the changes made in an array at a particular index appear in the DOM, we cannot use the typical way of adding elements to the array which is:
There are two known issues when dealing with reactivity in arrays:
- Changing elements at a particular index.
- Changing the length of the array.
Solutions
To fix caveat one, we can use the Array.prototype.slice
method and Vue.set()
also.
Using Array.prototype.slice
:
Using Vue.set()
:
The syntax is: Vue.set(array, index, newValue)
Also, remember that we can use the .$set()
alias directly inside the component.
To read more on reactivity in Vue you can checkout the reactivity in-depth doc.