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.$el
updates.- 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
setTimeout
work inconsistently when the delay is0
? setTimeout
seems hacky. Is there a "propper" way to force a UI update?