Vue.js: Synchronization of props may not happen instantly

Struggling with using vue.js to synchronize a prop between parent and child components. The challenge is that sync relies on events, so every time I update the value, I have to wait for $nextTick before seeing the update. It's cumbersome to include $nextTick every time I make a change. Is there a way to make the event/prop update happen instantly?

Here's the code snippet:

<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>

And the corresponding JavaScript:

const EVENT_UPDATE_BAR = "update:bar";

Vue.component("foo", {
    props:["bar"],
    computed:{
        _bar:{
            get:function(){
                return this.bar;
            },
            set:function(value){
                //Although mutating the prop here fixes the issue, it triggers a warning about prop mutation...
                //this.bar = value;
                this.$emit(EVENT_UPDATE_BAR, value);
            }
        }
    },
    methods:{
        handler_button_click:function(){
            //Noticing that $nextTick must be called before the value is updated
            this._bar = 5;
            //Displaying old value - the event/prop update hasn't fully propagated down to the child component
            alert("bar: " + this._bar);
        }
    }
});

new Vue({
    el:"#app",

    data:{
        bar:1
    }
});

Check out the live example on CodePen: https://codepen.io/koga73/pen/MqLBXg

Answer №1

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.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with box shadow appearing incorrectly as element content increases in size while the body has an image background

After applying a box shadow to the header div, I noticed that the box shadow doesn't display properly when the hidden elements within the header are revealed. <div id="header"> <div id="logo"> <a href="#"><img src="logo.png" ...

Tips for setting up a blog using nodejs and express.js

Hello everyone, I could really use some assistance. I am trying to figure out how to set up a blog using NodeJS specifically with ExpressJS, including basic functions like deleting, adding, and removing posts and comments, as well as standard authenticati ...

Element enclosed within a territory of mongoose Schema

In the midst of developing an API that provides detailed information about laptops, I am utilizing Node.js and MongoDB with Mongoose. The schema I am working with is as follows: const productSchema = mongoose.Schema( { name: { type: String, ...

When processing UTF-8, REST only acknowledges English characters and ignores any other characters

When sending an AJAX request in UTF8 to a server that uses REST, any part that contains non-English characters is disregarded. I am working with Java on the server side with REST, and the client sends AJAX requests in UTF8 that may include Hebrew words. ...

Printing in ASP.Net without displaying a dialog box

Is there a way for my web application to automatically print a popup page without prompting the client to choose a printer? I am looking for guidance on implementing silent printing in ASP.Net using java-script or ajax, or any other suitable solution for ...

Creating identical height columns with uniform inner elements is a problem that needs to be solved with caution. The proposed solution

Issue: I need to create a responsive layout with 5 columns, each containing an image, title, and text. The goal is to align the images separately, titles together, and texts individually while ensuring that all elements in a row have the same height. Solu ...

A guide to integrating flow (flowtype) into nuxt: step by step instructions

I'm looking to incorporate flow support into my webpack and babel-powered nuxt project. Does anyone have a working example I can refer to? After running flow check, I noticed no errors. However, when I run yarn run dev, I encounter a syntax error. ( ...

Is there a way to eliminate the legend symbol for just one legend in Highcharts?

Looking to customize a legend in Highcharts but facing limitations due to Plot Lines and Bands not having legends. To work around this, I have added an empty series that acts as a toggle for showing/hiding plot lines. Since my plot lines are vertical, I im ...

What is the best way to make an HTML form show fields depending on certain conditions?

Initially, I created an index page containing a form with various fields. The utility was built to handle all the fields, but now there's been a change in requirements. What I need is for only the Controller Type and Test Type fields to be displayed f ...

Have developers created an event trigger for when google maps controls finish loading?

While I am aware of the tilesloaded event, it appears that the controls load after this event. My goal is to use jQuery to retrieve the controls, but I am struggling to identify the appropriate event to listen for. ...

Error message: Impossibile to locate module 'formik' in 'C:Live projectsNew folder (2)src\_metronicpartialsmodalscreate-app'

"dependencies": { "@formatjs/intl-pluralrules": "^4.0.28", "@formatjs/intl-relativetimeformat": "^9.1.7", "@fortawesome/fontawesome-free": "^5.15.3", "@popperjs/core": "~2.10.1", "animate.css": "^4.1.1", "apexcharts": "^3.27.1", ...

Error: Unable to access undefined properties while trying to read 'add' value. Issue identified in the code related to "classlist.add" function

I am currently facing an issue where I receive the error message: Uncaught TypeError: Cannot read properties of undefined (reading 'add') when trying to add a class to a div using a button. After researching on Stack Overflow, I stumbled upon a ...

Displaying a static image on an HTML5 canvas without any movement

As a novice in canvas game development, I must apologize for my lack of knowledge. I have an image with dimensions 2048px width and 1536px height that needs to be placed within a canvas (the width and height vary on different devices). While I am able to ...

Contrasts in the immutability strategies of Vuex and Redux

After exploring Vuex and noticing how simple it is to mutate states with mutation handlers using basic assignment, I am currently delving into redux. I have come to realize that redux emphasizes immutability, which can make coding a bit more verbose. This ...

What effect does setting AutoPostBack to "true" in an ASP dropdownlist have on the fireEvent() function?

I am currently working on an aspx page. This page includes three dropdown lists and a button, all of which are populated dynamically based on the code written in the code-behind file (.cs file). To achieve this, I need to utilize two event handler methods ...

Identifying the Occurrence of a Partial Insertion in Rails through JavaScript/jQuery

Is there a way to determine if a partial is currently visible using JavaScript? Let's simplify this with some pseudo-code to explain my question - In this scenario, in my controller: def index if (request.xhr?)//coming from pagination ajax requ ...

What steps do I need to take to adjust this function based on the timezone?

Is there a way to retrieve the current time based on a specific timezone of my choice? let getCurrentTime = () => { var today = new Date(); var hh = String(today.getHours()) var mm = String(today.getMinutes()) //January is 0! var ss = ...

exploring div element(s) with jQuery

My HTML page contains multiple div elements in the body. I have also included buttons with associated click functions in jQuery to change the background-color of a div element based on the button pressed. However, I'm facing an issue at the 'term ...

Creating a new row does not result in the creation of a new span displaying the character count message

Every description field should have its own character counter, with different SpanIDs displayed in respective SpanIds for each new row. How can this be achieved? <div class="row"> <div class="col-s ...

The issue that arises is that only the initial button is able to successfully trigger the opening of

My goal is to create a forum where users can reply to posts by clicking on a "Reply" button that triggers a Bootstrap modal. However, I am facing an issue where the modal only opens when clicking on the first button in a row due to it being placed within a ...