2
votes

I have seen many questions and answer but they don't solve my problem, I'm just trying to show/hide when I click in the parent components menu button the drawer should open, after the first-time load it works fine but when I close this it shows me this error. I just want to pass true or false in the props

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: "drawer"

This what I'm trying to do.

In the parent

<template>
    <div @click="drawer = true" class="hamburger">
       <span></span>
       <span></span>
       <span></span>
    </div>

   <mobile-drawer-menu :drawer="drawer"/>
</template>

<script>
   import MobileDrawerMenu from "./MobileDrawerMenu";

   export default {
     components : {
        MobileDrawerMenu
    },

     data() {
        return {
            drawer : false,
        }
     },

   }
</script>

In child

<template>
    <div v-if="drawer" class="fixed top-0 left-0 z-200">
        <div @click="drawer = false" class="overlay"></div>
        <div class="drawer-wrapper">
            <div class="drawer-close">
               <div class="flex items-center justify-end">
                  <svg @click="drawer = false"></svg>
               </div>
            </div>
        </div>
    </div>                     
</template>

<script>
   export default {
      name: "MobileDrawerMenu",
      props : {
        drawer : {
            type : Boolean,
            required : true
        }
     },
   }
</script>
2

2 Answers

2
votes

You can use .sync modifier, and update the prop with $emit :

<template>
    <div @click="drawer = true" class="hamburger">
       <span></span>
       <span></span>
       <span></span>
    </div>

   <mobile-drawer-menu :drawer.sync="drawer"/>
</template>

<script>
   import MobileDrawerMenu from "./MobileDrawerMenu";

   export default {
     components : {
        MobileDrawerMenu
    },

     data() {
        return {
            drawer : false,
        }
     },

   }
</script>

Child

<template>
    <div v-if="drawer" class="fixed top-0 left-0 z-200">
        <div @click="$emit('update:drawer', false)" class="overlay"></div>
        <div class="drawer-wrapper">
            <div class="drawer-close">
               <div class="flex items-center justify-end">
                  <svg @click="$emit('update:drawer', false)"></svg>
               </div>
            </div>
        </div>
    </div>                     
</template>

<script>
   export default {
      name: "MobileDrawerMenu",
      props : {
        drawer : {
            type : Boolean,
            required : true
        }
     },
   }
</script>

JsFiddle: https://jsfiddle.net/hansfelix50/176oba9n/

1
votes

You shouldn't mutate your prop in the child component. You can emit event and close in parent controller or just let drawer be only in child component and toggle open via function, using ref:

Parent:

<template>
    <div @click="open" class="hamburger">
       <span></span>
       <span></span>
       <span></span>
    </div>

   <mobile-drawer-menu ref="modal"/>
</template>

<script>
    import MobileDrawerMenu from "./MobileDrawerMenu";

    export default {
        components : {
            MobileDrawerMenu
        },
        methods: {
            open() {
                this.$refs.modal.open();
            }
        },
    }
</script>

Child:

<template>
    <div v-if="drawer" class="fixed top-0 left-0 z-200">
        <div @click="close" class="overlay"></div>
        <div class="drawer-wrapper">
            <div class="drawer-close">
               <div class="flex items-center justify-end">
                  <svg @click="close"></svg>
               </div>
            </div>
        </div>
    </div>                     
</template>

<script>
    export default {
        name: "MobileDrawerMenu",
        data: () => ({
            drawer: false
        }),
        methods: {
            open() {
                this.drawer = true;
            },
            close() {
                this.drawer = false;
            }
        }
    }
</script>

As you see, you can access child methods(and state values) using ref. More about ref here. Also you can do this using emit, if you need to keep drawer property in parent component, you can read about it here