Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with literal object props in template #4060

Closed
Katherina-Miao opened this issue Oct 29, 2016 · 14 comments
Closed

Problem with literal object props in template #4060

Katherina-Miao opened this issue Oct 29, 2016 · 14 comments

Comments

@Katherina-Miao
Copy link

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.

@paulpflug
Copy link

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?

@fnlctrl
Copy link
Member

fnlctrl commented Oct 30, 2016

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

@chrisvfritz
Copy link
Contributor

chrisvfritz commented Oct 31, 2016

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

@fnlctrl
Copy link
Member

fnlctrl commented Oct 31, 2016

@chrisvfritz Hmm that seems possible, but I'm not familiar with the template compiler.. @defcc any ideas?

@HerringtonDarkholme
Copy link
Member

HerringtonDarkholme commented Oct 31, 2016

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?

@defcc
Copy link
Member

defcc commented Oct 31, 2016

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 ?

@posva
Copy link
Member

posva commented Oct 31, 2016

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

@defcc
Copy link
Member

defcc commented Oct 31, 2016

Means non-dynamic value, not just object literals :)

for example

:arr="[1]" :obj="{}" :id="1"

@chrisvfritz
Copy link
Contributor

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.

@yyx990803
Copy link
Member

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

@coolzjy
Copy link
Contributor

coolzjy commented Nov 6, 2016

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

@Noemi-
Copy link

Noemi- commented Jun 3, 2019

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.

@chandanwtb
Copy link

chandanwtb commented Sep 20, 2020

When I am using format: 'DD/MM/YYYY', Calendar is working fine but when format: 'DD/MM/YYYY h:mm:ss' Calendar is Not working.
image

But When format: 'DD/MM/YYYY'

image

@danielgindi
Copy link

Just bit me in the behind too. The vue eslint plugin should detect this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests