Skip to content

vue/no-mutating-props option: {"propProps": false} #1371

Closed
@cdrini

Description

@cdrini

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 )

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions