2.6.11
<template>
<div id="app">
<div>
<span :id="method1()" />
<input :id="method2()" type="text" />
</div>
<div
@mouseenter="message = 'huh???'"
@mouseleave="message = ''"
style="margin-top: 20px;"
>
Hover me, and the 'message' prop will get updated. <br />
But method1() and method2() are also called.
</div>
<h1>{{ message }}</h1>
</div>
</template>
<script>
export default {
data: function () {
return {
message: ""
};
},
methods: {
method1() {
console.log("method1 called");
return 'first';
},
method2() {
console.log("method2 called");
return 'second';
}
}
};
</script>
https://codepen.io/rmirabelle/pen/bGpodLx
Open console. Observe output while hovering the target element.
method1 and method2 are called once when loading. When hovering, the message property is updated. Only the h1 element, which outputs the message is updated.
The message property is updated. But instead of re-rendering just the h1 that outputs the message, the entire component appears to be re-rendered, thus re-triggering all methods bound to other elements. This occurs seemingly regardless of how the other element attributes are bound. (e.g. .stop, .prevent, etc.)
Given how simple this example is, I feel like I must be missing something fundamental about Vue reactivity. Neither of the elements bound to method1 or method2 observes or uses message. Nor is mouseenter attached to those elements. So why are the methods being called repeatedly?
Every Vue component, including the root, has a render function (which is compiled from the template code) and that render function will be called every time the component's state (it's prop, data, and computed properties) gets updated. In your case, updating message is updating the component's state and thus component's render function is getting called. We can take a look at the render function compiled from your code and it's obvious why method1 and method2 is called on every update:
function render() {
with(this) {
return _c('div', {
attrs: {
"id": "app"
}
}, [_c('div', [_c('span', {
key: "foo",
attrs: {
"id": method1()
}
}), _c('input', {
key: "bar",
attrs: {
"id": method2(),
"type": "text"
}
})]), _c('div', {
staticStyle: {
"margin-top": "20px"
},
on: {
"mouseenter": function($event) {
message = 'huh???'
},
"mouseleave": function($event) {
message = ''
}
}
}, [_v(
"Hover me, and the 'message' prop will get updated."
), _c('br'), _v(
"But EVERY method will also be called.")]), _c('h1', [
_v(_s(message))
])])
}
}
_We can easily inspect template compilation result, i.e. the render function, using a nice website: vue-compiler-online. Thanks to @Magiccwl_
Indeed, vue has some diffing algorithm that provides a performant update, trying to prevent unnecessary updates. But this optimization is for DOM operations, in other words, unnecessary DOM operations would be avoided wherever it's possible to do so.
I cannot see the original intention of using methods to produce those two ids, and I would say this could be a [code smell]. That said, assuming there is a plausible reason to do that, [computed properties] might help you with the problem since they're [cached].
BTW, mouseenter/mouseleave are irrelevant here since they're merely something cause component's state to update. It could be button clicks or even periodic timers.
Comopnent state gets update -> render function gets called -> method1 and method2 get called (they're called within render function. Just normal function calls, no magic at all)
This is expected as @Nandiin amazingly explained! Thank you @Nandiin !
This was helpful thanks. My example was contrived to minimize clutter. I incorrectly assumed the method calls would be 'cached' as computed properties are. This example cleanly demonstrates how untrue that is.
Most helpful comment
Every Vue component, including the root, has a
renderfunction (which is compiled from the template code) and thatrenderfunction will be called every time the component's state (it's prop, data, and computed properties) gets updated. In your case, updatingmessageis updating the component's state and thus component'srenderfunction is getting called. We can take a look at therenderfunction compiled from your code and it's obvious whymethod1andmethod2is called on every update:_We can easily inspect template compilation result, i.e. the render function, using a nice website: vue-compiler-online. Thanks to @Magiccwl_
Indeed, vue has some diffing algorithm that provides a performant update, trying to prevent unnecessary updates. But this optimization is for DOM operations, in other words, unnecessary DOM operations would be avoided wherever it's possible to do so.
I cannot see the original intention of using methods to produce those two ids, and I would say this could be a [code smell]. That said, assuming there is a plausible reason to do that, [computed properties] might help you with the problem since they're [cached].