12
votes

I'm trying to create a modal but I'm getting this error only when I close it:

[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: "value"

found in

---> <PanelDesconectarModal> at resources\assets\vue\PanelDesconectarModal.vue
       <VNavigationDrawer>
         <PanelDrawer> at resources\assets\vue\PanelDrawer.vue
           <VApp>
             <PanelRoot> at resources\assets\vue\PanelRoot.vue
               <VApp>
                 <Root>

PanelDesconectarModal.vue

<template>
    <v-dialog v-model="value" max-width="350">
        <v-card :dark="($theme === 'dark')">
            <v-card-title class="headline">Desconectar</v-card-title>
            <v-divider></v-divider>
            <v-card-text>Você tem certeza que deseja desconectar-se?</v-card-text>
            <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn flat @click.native="closeDialog">Cancelar</v-btn>
                <v-btn :color="$color" flat="flat" @click.native="desconectar">Desconectar</v-btn>
            </v-card-actions>
        </v-card>
    </v-dialog>
</template>

<script>
    export default {
        name: 'panel-desconectar-modal',
        props: ['value'],
        methods: {
            closeDialog() {
                this.value = false;
            },
            desconectar() {
                this.closeDialog();

                window.location = this.$route + '/panel/desconectar';
            }
        }
    }
</script>

Using ProgressDesconectarModal.vue, showDesconectar is a data variable

<panel-desconectar-modal :value="showDesconectar"></panel-desconectar-modal>
4
I already answered similar question, but can't link it because for some reason OP didn't vote on it.Traxo

4 Answers

21
votes

This happens because you have props value in your v-model.

Do not do that, as that will mutate the prop(value) when v-model changes (you should only change data values with v-model afaik, but in this case, you don't even need additional data variable).

Since vuejs v2.3.0, it is suggested to emit value to the parent, so that parent changes it, and it is then passed to child component.


in v-dialog component

remove v-model and replace it with :value="value" @input="$emit('input')"

And your function:

closeDialog() {
    this.$emit('input');
}

In panel-desconectar-modal component use v-model="showDesconectar".


This will work because:

<input v-model="something"> is syntactic sugar for:

<input   
    v-bind:value="something"
    v-on:input="something = $event.target.value">

Here is working example pen which I provided in an answer to similar question.

1
votes

You should not mutate the props in your child component. You can only mutate the object but not primitives. So, you can use data option or a computed property:

data() {
  return {
    childValue: this.value; // initialize props value
  }
}

Now, you can change the childValue:

closeDialog() {
   this.childValue = false;
},

Make sure to use childValue everywhere inside your child component instead of value props.

1
votes

This is really the moment to ask yourself "Do I really need a prop? Can I do this with data? Am I here because I mistakenly put some state in Vue component?"

If you're the author of the page and the component, and the component only appears once on the page, there is no good reason to use props. If you need props because the component is repeated for all the lines in an array, make the prop just the array index, so the component can directly modify the source array in the store. Vue components should not contain state, especially state that needs to be shared, and do not enjoy being tightly bound to each other. The parent-child relationship arises out of the chance of their placement in the DOM tree, (children occur inside the markup of parents). This is like a chance meeting in a nightclub. The child may have nothing else to do with the parent. The hierarchy of your source data should be expressed, independently of your markup, in the structure of your store. Your Vue components, where possible, should have an intimate two way relationship with the store, and not talk much to each other :-)

-1
votes

In the relevant Vue doc they don't have examples with default values, so these answers are to be found elsewhere. I needed a solution to create a component with a default value, but the input would always spring back to what it was before when it loses focus, or it gave the "avoid mutating a prop directly" error. Creating a mutable property and setting its value in the created event solved it for me:

data()
{
    return {
        text: null
    };
},

props: {
    properties: Object,
    value: String
},

created()
{
    this.text = this.value;
}