javascriptvue.jsmutationanti-patternsvue-props

How to make a sample that shows the 'Props are overwritten when re-rendering' anti pattern


I would like to be convinced that 'Props are overwritten when re-rendering' is an anti pattern.

const MyButton = Vue.extend({
  props: {
    obj: {}
  },
  template:
    "<button @click=\"obj.text = 'Value'+Math.round(Math.random()*100)\">Change text in child ({{obj.text}})</button>"
});

const app = new Vue({
  el: "#main",
  data: {
    obj: { text: "Value2" }
  },
  components: {
    MyButton
  },
  template: `
<div>
  <Button @click='obj.text = "Value"+Math.round(Math.random()*100)'>Change text in parent ({{obj.text}})</Button><br>
  <MyButton :obj='obj'/> 👈 Pressing here 'mutate' the prop. It is an anti-pattern (Props are overwritten when re-rendering). But it seems to work just fine, how to change this sample so it shows the anti-pattern problem? (https://eslint.vuejs.org/rules/no-mutating-props.html)
</div>`
});

UPDATED Codepen: https://codepen.io/SVSMITH/pen/LYrXRzW

Can anyone help?


Solution

  • In your example you are actually not mutating the prop, because what you send in to the child is a reference to an object. This reference stays the same. See what happens if you change the template code in your child to:

    "<button @click=\"obj = {}\">Change text in child ({{obj.text}})</button>"
    

    Then you will see that the prop is overwritten and the value of the child differs from that in the parent. When the parent updates the value, the updated value in the child will be overwritten. Which can cause serious and hard to find bugs. Therefore use emit in the child to update the value in the parent, which will update the child value through the prop.

    If you have a lot of these props and emits, you should look into using a store like Pinia.