I would like to force the UI to update midway through an event loop cycle.
Vue.nextTick
Vue.nextTick seems to provide you with an updated version of vm.$el, but doesn't actually cause the UI to update.
CodePen: https://codepen.io/adamzerner/pen/RMexgJ?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A"
Vue.nextTick(function () {
// vm.$el.children[0].textContent === "Value: B"
// but the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
});
}
vm.$forceUpdate
vm.$forceUpdate doesn't appear to do anything at all.
- It doesn't appear to change the value of
vm.$el. - It doesn't appear to update the UI.
CodePen: https://codepen.io/adamzerner/pen/rdqpJW?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A"
vm.$forceUpdate();
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}
v-bind:key
v-bind:key also doesn't appear to do anything at all:
- It doesn't appear to change the value of
vm.$el. - It doesn't appear to update the UI.
Codepen: https://codepen.io/adamzerner/pen/WzadKN?editors=1010
HTML:
<div id="example">
<p v-bind:key="message">Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}
computed
Using a computed property, as this popular answer recommends, also doesn't appear to do anything:
- It doesn't appear to change the value of
vm.$el. - It doesn't appear to update the UI.
CodePen: https://codepen.io/adamzerner/pen/EEdoeX?editors=1010
HTML:
<div id="example">
<p>Value: {{ computedMessage }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
computed: {
computedMessage: function () {
return this.message;
},
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}
Promise (added in edit)
Using promises doesn't work either.
CodePen: https://codepen.io/adamzerner/pen/oqaEpV?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
var promise = new Promise(function (resolve, reject) {
for (var i = 0; i < 10000000; i++) {}
resolve();
});
promise.then(function () {
vm.message = 'C';
});
}
setTimeout
setTimeout is the only thing that seems to work. But it only works consistently when the delay is 100. When the delay is 0, it works sometimes, but doesn't work consistently.
vm.$elupdates.- The UI updates.
CodePen: https://codepen.io/adamzerner/pen/PRyExg?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
setTimeout(function () {
// vm.$el.children[0].textContent === "Value: B"
// the UI has updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}, 100);
}
Questions
- Why don't
Vue.nextTick,vm.$forceUpdate,v-bind:key, or computed properties work? - Why does
setTimeoutwork inconsistently when the delay is0? setTimeoutseems hacky. Is there a "propper" way to force a UI update?