Description
What rule do you want to change?
vue/no-mutating-props
Does this change cause the rule to produce more or fewer warnings?
A new, {"propProps": false}
option would cause it to produce fewer warnings.
How will the change be implemented? (New option, new default behavior, etc.)?
New option: {"propProps": false}
(i.e. Don't error when mutating prop properties)
Please provide some example code that this change will affect:
<template>
<div>
<input type="range" v-model.number="point.x" >
<input type="range" v-model.number="point.y" >
</div>
</template>
<script>
export default {
props: {
point: {
type: Object,
required: true
}
},
}
</script>
What does the rule currently do for this code?
Trigger an error
What will the rule do after it's changed?
When the default option is set ({"propProps": true}
), the error will trigger. When the option is set as {"propProps": false}
, it will not trigger an error.
Additional context
(Note there are some issues in the past suggesting this rule be loosened (#1339 , #1314; cc @leosdad @pimlie @decademoon ); here I'm suggesting an option be added instead)
My main reason for wanting an option here, is that modifying the reference of a prop (e.g. this.myProp = 3
) will cause actual run-time warnings from Vue, cause unexpected behaviour, and is deprecated:
Due to the new rendering mechanism, whenever the parent component re-renders, the child component’s local changes will be overwritten. - https://vuejs.org/v2/style-guide/#Implicit-parent-child-communication-use-with-caution
Here's the warning Vue throws:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "number"
Modifying the value of a prop (but leaving the reference the same) (e.g. this.myProp.x = 3
), does not throw runtime warnings, and (I believe) does not cause any unexpected behaviour—it's just a code style decision. As long as the actual reference to the object remains unaltered, Vue should not have any issues.
Here's a sandbox with these two cases for reference: https://codesandbox.io/s/elegant-lederberg-p1ilc
(Note: This is the same way that const
behaves in JS, so shouldn't be unexpected to most developers:
const x = 3;
x = 7; // Error!
const y = {};
y.foo = 3; // This is fine; it's the _reference_ that's const, not the value.
y = 20; // Error
)
I would love it if I could configure linting to error for reference prop modifications (which I need to fix), but to ignore value prop modifications (which I often prefer using in my code). If an option is added called, say {"propProps": true}
, then I would use it instead of disabling the rule entirely.
P.S. How would one implement my code snippet above without prop value modification? The nicest way I can think of is something like this, which doesn't look particularly better to me.
<template>
<div>
<input type="range" v-model.number="x" >
<input type="range" v-model.number="y" >
</div>
</template>
<script>
export default {
props: {
value: {
type: Object,
required: true
}
},
data() {
return {
x: this.value.x,
y: this.value.y,
};
},
watch: {
// Duplicate; could create a `mounted` method and use `$watch` to watch everything
x(newVal) { this.$emit('input', { x: newVal, y: this.y } },
y(newVal) { this.$emit('input', { x: this.x, y: newVal } },
}
}
</script>
(Similar to https://simonkollross.de/posts/vuejs-using-v-model-with-objects-for-custom-components )