TheDevGuy
TheDevGuy

Reputation: 703

Avoid props mutation in vueJS

I have a component with props ans I want to modify the value from false to true but I have a message form chrome console

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders

In the parent component I have a function (myFunction) who take one argument( value ).

I need to keep my argument like this, but I also need to retrieve the value of the emit from the child component to change the value of myData without mutate the props in child.

https://codesandbox.io/s/distracted-wiles-w8vwf

<template>
  <div>
    <p>The number is {{number}}</p>
    <Child :MyProp="myData" @on-click-btn="myfonction(5)"/>
  </div>

</template>

<script>
import Child from "./components/Child.vue";

export default {
  data() {
    return {
      myData: 'button',
      number: 1
    };
  },
  components: {
    Child
  },
  methods: {
    myfonction(value) {
      this.number = value;
    }
  }
};
</script>

thanks

Upvotes: 0

Views: 267

Answers (2)

Shivam Singh
Shivam Singh

Reputation: 1731

It's an anti-pattern to modify prop directly in Vue

Instead, you can an emit an event from the child & modify the data in the parent which is being passed as the prop to the child as below:

parent.vue

<template>
  <child 
   MyProp="myData"
   @on-click-btn="handleClick" // [2] listen to the event & attach an handler to it
  />
</template>

export default {
 data () {
  return {
   myData: false
  }
 },
 // [3] event handler gets called when event is triggered ie. at user's click
 handleClick (currentValue) {
  // [4] modify the data, that is being passed as prop to the child, so that child recieves the updated data
  this.myData = !currentValue
 }
}

child.vue

<template>
  <button @click="handleClick">click me, I am {{ MyProp }}</button>
</template>

export default {
 props: ['MyProp'],
 method: {
  handleClick () {
   // [1] emit an event on user's click & pass the current prop value to it
   this.$emit('on-click-btn', this.MyProp)
  }
 }
}

demo

Upvotes: 2

Christian Carrillo
Christian Carrillo

Reputation: 2761

you can use the sync modifier:

Vue.component('child', {
  template: '#child',
  props: {
    val: {
      type: String, required: true
    }
  },
  methods: {
    handleInput(event) {
      this.$emit('update:val', event.target.value)
    }
  }
})

new Vue({
  el: '#app',
  data(){
    return {
      value: ''
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>

<script type="text/x-template" id="child">
  <input @input="handleInput">
</script>

<div id="app">
  <child :val.sync="value"></child>
  <div>{{ value }}</div>
</div>

Upvotes: 2

Related Questions