After analyzing the provided example, I have integrated watchers for the bar
property in both the parent and child components. Furthermore, console.log
statements have been incorporated to monitor the data flow between these components:
const EVENT_UPDATE_BAR = "update:bar";
Vue.component("foo", {
props:["bar"],
computed:{
_bar:{
get:function(){
console.log('_bar getter is called')
return this.bar;
},
set:function(value){
console.log('_bar setter is called')
this.$emit(EVENT_UPDATE_BAR, value);
}
}
},
methods:{
handler_button_click:function(){
console.log('handler_button_click is called')
this._bar = 5;
console.log('this._bar is accessed with value: ', this._bar);
this.$nextTick(() => {
console.log('next tick handler is called')
})
console.log('handler_button_click finishes')
}
},
watch: {
bar() {
console.log('child bar watcher is called')
}
}
});
new Vue({
el:"#app",
data:{
bar:1
},
watch: {
bar() {
console.log('parent bar watcher is called')
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<foo inline-template v-bind:bar.sync="bar">
<div>
<button v-on:click="handler_button_click">Set to 5</button>
</div>
</foo>
<span>bar: {{bar}}</span>
</div>
Upon careful examination, it becomes evident that the handler_button_click
function is executed first, followed by the invocation of the get
and set
methods for the _bar
computed property. However, the watchers for the bar
property are triggered only after the handler_button_click
function completes its execution. This indicates that the value emitted by the child component's $emit
call is processed by the parent component only after the handler_button_click
function is done running.
VVue's recommended way to synchronize the properties of the parent and child components within the handler_button_click
function is to utilize the $nextTick
function. This function postpones the execution of its handler until the DOM updates have finished. By ensuring that all data changes in both parent and child components are resolved before the DOM rendering concludes, synchronization can be achieved effectively.
In essence, if the main goal is for the child component's _bar
property to update immediately upon assignment, without immediate updates in the parent scope, watchers could be used instead of computed properties. Through this approach, the child's property updates instantaneously while the parent's property synchronization occurs after the next tick.
Here's an updated version of the example:
const EVENT_UPDATE_BAR = "update:bar";
Vue.component("foo", {
props: ["bar"],
data() {
return {
value: this.bar,
};
},
methods: {
handler_button_click() {
this.value = 5;
alert("bar: " + this.value);
}
},
watch: {
value(val) {
this.$emit(EVENT_UPDATE_BAR, val);
},
bar(val) {
this.value = val;
}
}
});
new Vue({
el: "#app",
data() {
return {
bar: 1
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<foo inline-template v-bind:bar.sync="bar">
<div>
<button v-on:click="handler_button_click">Set to 5</button>
</div>
</foo>
<span>bar: {{bar}}</span>
</div>
I have renamed the _bar
property to value
to adhere to best practices, as properties prefixed with an underscore are not watched since they are not proxied to the Vue instance.