Ashtav
Ashtav

Reputation: 2966

Avoid mutating a prop directly when use vue component

I create an alert component in vue, like this

<template>
   <div class="alert-bg" v-if="view">
    <div class="content">
        <div class="message"> {{message}} </div>
        <div class="alert-control text-right mt-4">
            <button class="btn btn-secondary" @click="onCancel" v-html="cancel"/>
            <button :class="btnStyle" class="btn ml-2" v-html="ok" @click="onSubmit"/>
        </div>
    </div>
  </div>
</template>

<script>
    import $ from 'jquery';
    import 'imports-loader?window.jQuery=jquery,this=>window!widgster';

    export default { 
        name: 'Alert',
        props: {
            message: { default: 'Lorem ipsum dolor sit amet consectetur' },
            cancel: { default: 'Cancel' },
            ok: { default: 'Yes' },
            btnStyle: { default: 'btn btn-primary' },
            view: { default: false }
        },

        methods: {
            onCancel(){
                this.view = false;
            },

            onSubmit(){
                this.$emit('onSubmit');
            }
        },

    };
</script>

then in main page I use it like this,

// html
<button class="btn btn-secondary" @click="confirm" v-html="'Confirm'"/>
<Confirm :view="alert.view"/>

// script
import Confirm from '@/components/modals/alert/alert';

export default {
  name: "Product",
  components: { Confirm },
  data() {
    return {
      alert: { view: false },
    }
  },

  methods: {
     confirm(){
        this.alert.view = true; // show alert
     }
  }
}

When I click confirm button, it's success to show alert, when I click cancel button the alert is close but I got error like this

[Vue warn]: 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: "view"

then when I click confirm button again, the alert does not appear, how I can solve this problem? thank you very much

Upvotes: 0

Views: 215

Answers (2)

DShadrin
DShadrin

Reputation: 161

As vue.js guide says:

All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand.

So you have to create component own state and and then modify state inside your component. Like this:

<script>
    import $ from 'jquery';
    import 'imports-loader?window.jQuery=jquery,this=>window!widgster';

    export default { 
        name: 'Alert',
        data() {
            return{
                componentView: this.view
            }
        },
        props: {
            message: { default: 'Lorem ipsum dolor sit amet consectetur' },
            cancel: { default: 'Cancel' },
            ok: { default: 'Yes' },
            btnStyle: { default: 'btn btn-primary' },
            view: { default: false }
        },

        methods: {
            onCancel(){
                this.componentView = false;
            },

            onSubmit(){
                this.$emit('onSubmit');
            }
        }

    };
</script>

Upvotes: 0

talkhabi
talkhabi

Reputation: 2759

You are changing the prop directly from the child component(as vue said). So the true way is:

methods: {
  onCancel(){
    // this.view = false; <--- is wrong way
    this.$emit('update:view', false)
  }
  // ...
},

Then in parent pass it like this:

<Confirm :view.sync="alert.view"/>

Upvotes: 1

Related Questions