Although there are many similar questions on this topic, mine has a unique twist. After delving into reactivity in depth, I feel like I have a solid grasp of the concept. However, one thing continues to baffle me:
Summary:
Why does a watched property detect changes when initialized using
currentValue = Object.assign({}, currentValue, initValue)
, but not with a straightforward assignment like currentValue = initValue;
?
I have an object called scoreRules
registered on the model of my Vue component.
In the mounted
hook,
- I reset the model's
scoreRules
by doing this:
this.$data.scoreRules = initScoreRules;
(I'm using initScoreRules
as a prop which is locally declared below for this question).
- I watch for changes in
scoreRules
and log "score has been changed" whenever the object changes.
This code snippet illustrates the scenario:
new Vue({
el: '#app',
data() {
return {
scoreRules: {
type: 'number',
minimum: null,
maximum: null
}
}
},
mounted() {
let initScoreRules = {type: 'number'};
this.$data.scoreRules = initScoreRules;
this.$watch('scoreRules', ()=>{console.log("score has been changed")}, {deep: true});
}
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
</head>
<body>
<div id="app">
<span>Minimum score</span>
<input type="number" name="minimumScore" v-model.number="scoreRules.minimum" />
</body>
</html>
When typing in the input field, the watch doesn't capture this change and nothing gets logged to the console.
If I then reinitialize scoreRules
using
this.$data.scoreRules = Object.assign({}, this.$data.scoreRules, initScoreRules);
new Vue({
el: '#app2',
data() {
return {
scoreRules: {
minimum: null
}
}
},
mounted() {
let initScoreRules = {};
this.$data.scoreRules = Object.assign({}, this.$data.scoreRules, initScoreRules);
this.$watch('scoreRules', () => {
console.log("score has been changed")
}, {
deep: true
});
}
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
</head>
<body>
<div id="app2">
<span>Minimum score</span>
<input type="number" v-model.number="scoreRules.minimum" />
</div>
</body>
</html>
The changes are now detected and recorded in the console. But why? My suspicion is that it relates to the inner workings of JavaScript itself, although the exact mechanism still eludes me.