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 · 12 comments

Comments

Projects
None yet
10 participants
@Katherina-Miao
Copy link

commented Oct 29, 2016

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

This comment has been minimized.

Copy link

commented Oct 29, 2016

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

commented Oct 31, 2016

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

@HerringtonDarkholme

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

commented Oct 31, 2016

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

for example

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

This comment has been minimized.

Copy link
Member

commented Oct 31, 2016

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

This comment has been minimized.

Copy link
Member

commented Nov 1, 2016

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

This comment has been minimized.

Copy link
Contributor

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-

This comment has been minimized.

Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.