Problem with literal object props in template
Katherina-Miao opened this issue ยท 14 comments
Vue.js version
2.0.3
Reproduction Link
http://codepen.io/KathyMiao/pen/XjLJxE?editors=1010
Steps to reproduce
When the template has literal object props, it may cause template re-render.
What is Expected?
number:1
What is actually happening?
number:100
This usage is very common with vue 1.x. However, it causes problem in vue 2.x with no warning and recommendation. It is not easy to debug and find out the cause. Warning message and usage description in vue guide will be helpful.
The problem is within your watch..
watch: {
prop: function(val,oldVal) {
// val will be {}
// oldVal will be {}, too, but another instance, so they are not equal
}
}
You can do two things:
- make a deepEqual on val & oldVal to only emit when the content really changed.
- don't use literals in props, maybe pass down a computed value instead?
Using object literals in template as prop should indeed be warned against, since in 2.0 it means creating a new object every time the component updates... Though I can't seem to think of a way to detect it at runtime. Maybe we can add a warning in the docs? @chrisvfritz
@fnlctrl When parsing the template, could we add object/array literals to a component instance-scoped cache, so that their reference remained the same between updates?
@chrisvfritz Hmm that seems possible, but I'm not familiar with the template compiler.. @defcc any ideas?
Seems impossible because Vue's parse is a simple regex scanner + recursive descendant parser, optimized for payload size. No real javascript expression parser is included.
Source: https://github.com/vuejs/vue/blob/dev/src/compiler/parser/html-parser.js#L16 and https://github.com/vuejs/vue/blob/dev/src/compiler/parser/html-parser.js#L196
Expression like :prop="'nested "quote"'"
is not supported.
IMHO, adding a warning in the doc is probably enough for now. For longer term, I think this check is better integrated in vue-template-validator or so?
I think there is no need to cache the literals just for the misusage of binding props,
maybe we could introduce a warning instead when parsing in dev mode ?
The use case is not clear to me. The example is just changing the number until it reaches 100
If we introduce the warning, what will it check? Using object literals is quite usual for class and style bindings. If we warn the user about that, we're kind of forcing him to fix it because nobody wants to leave a warning on their console ๐
I think it's good to tell the user to use a computed property instead but wanted to point out that
Means non-dynamic value, not just object literals :)
for example
:arr="[1]" :obj="{}" :id="1"
I think only objects and arrays are a problem though, because those are pass by reference in JS. Strings, numbers, and booleans are all immutable, so equal values will always share the same reference.
Either way, I'd like to avoid adding notes like this to the docs - even if we don't fix it. Not only is this an edge case, but the resulting behavior has nothing to do with Vue specifically, but would be the expected behavior for any JS lib with render functions.
I don't think there is a way to prevent what is happening in the original fiddle - it's expected behavior given how 2.0's render system works.
As for warning literal object/arrays, the tricky thing is it could be valid usage as long as the user doesn't attempt to mutate the value (which I believe is already warned against in the docs).
I'm also encountered this problem in my code, and I spend lots of time debugging without help of warning. I also search the docs for literal
keyword, and I only got two results (1/2), one of which even give an example of using object literals:
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
I think static prop is useful under many conditions. Static props' action in Vue 1.x is in line with expectations, but a little confusing in Vue 2.x (although I know how it works).
I also noticed that .once
modifier was removed in Vue 2.x. I don't think this modifier breaks one-way binding. On the contrary, I think it will be helpful in Vue 2.x to perform a static prop. So any idea of bringing it back? @yyx990803
I encountered this as well, when I try to bind an Array literal to a component's property. It spend me half day to realize that it is a "render function + Array literal property" issue, through several experiments and debug.
Just bit me in the behind too. The vue eslint plugin should detect this.