2.6.10
https://codepen.io/anon/pen/zQVRgG?editors=1010
Type something into the first field
Uncomment line 8 or 14 then try again
In console:
Render a
In console:
Render a
Render b
This is basically the same problem as with $listeners at https://github.com/vuejs/vue/issues/7257
It's because we read parent.attrs: https://github.com/vuejs/vue/blob/dev/src/core/instance/lifecycle.js#L260
Ah yep, missed that one.
Looks like we have c('field', { attrs: { "title": "b" } }), then title is removed at extractProps leaving an empty object, so the || emptyObject doesn't apply.
I'll leave this open as the fix will probably be different.
The workaround I'm using for now is to mutate a single object instead:
data: () => ({
$_attrs: {},
$_listeners: {},
}),
watch: {
// Work around unwanted re-renders: https://github.com/vuejs/vue/issues/10115
// Make sure to use `v-bind="$data.$_attrs"` instead of `v-bind="$attrs"`
$attrs: {
handler (val) {
for (const attr in val) {
this.$set(this.$data.$_attrs, attr, val[attr])
}
},
immediate: true
},
$listeners: {
handler (val) {
for (const listener in val) {
this.$set(this.$data.$_listeners, listener, val[listener])
}
},
immediate: true
}
},
https://codepen.io/anon/pen/rXpGbj?editors=1010
I 100% guarantee there's bugs in this btw.
The workaround I'm using for now is to mutate a single object instead:
data: () => ({ $_attrs: {}, $_listeners: {}, }), watch: { // Work around unwanted re-renders: https://github.com/vuejs/vue/issues/10115 // Make sure to use `v-bind="$data.$_attrs"` instead of `v-bind="$attrs"` $attrs: { handler (val) { for (const attr in val) { this.$set(this.$data.$_attrs, attr, val[attr]) } }, immediate: true }, $listeners: { handler (val) { for (const listener in val) { this.$set(this.$data.$_listeners, listener, val[listener]) } }, immediate: true } },https://codepen.io/anon/pen/rXpGbj?editors=1010
I 100% guarantee there's bugs in this btw.
Yes, need to delete attrs which wasn't in $attrs any more.
Consider this scenario:
<my-button v-if="visible" />
<my-button v-else detail />
If we toggle visible once, detail will be in $_attrs even visible is true.
I think the root cause is vue v-dom diff policy.
There are three ways to help this out:
v-show instead of v-if<my-button v-show="visible" />
<my-button v-show="!visible" detail />
key to these two components<my-button v-if="visible" key="a" />
<my-button v-else="visible" key="b" detail />
$attrs: {
handler (val) {
const oldKeys = Object.keys(this.$data.$_attrs)
for (const attr in val) {
this.$set(this.$data.$_attrs, attr, val[attr])
const index = oldKeys.indexOf(attr)
if (index > -1) {
oldKeys.splice(index, 1)
}
}
for (const attr of oldKeys) {
this.$delete(this.$data.$_attrs, attr);
}
},
immediate: true
},
Most helpful comment
The workaround I'm using for now is to mutate a single object instead:
https://codepen.io/anon/pen/rXpGbj?editors=1010
I 100% guarantee there's bugs in this btw.