Search code examples
javascriptvue.js

Change Boolean value in child component


In React I was able to update a Boolean value from the child component using a useState in a prop to pass a new value back and forward, however in Vue I'm struggling to do similar.

I have been able to pass the Boolean value to the child component by doing this:

Parent:

<template>
  <button @click="viewProduct()"
  <ChildComponent v-if="showProduct === true" :showProduct = showProduct />
</template>

<script setup>
  import { ref, defineProps } from 'vue'
  import ChildComponent from './ChildComponent.vue'
  
  let showProduct = ref(false)
  const viewProduct = (e) => {
      showProduct.value = true
  }
</script>

and I can see the value passed through to the child as a prop and I can use it in the child component.

However if I try to change the variable in the child component with something like this:

Child:

<template>
  <div class="close" @click="hidePDP()">X</div>
</template>

<script setup>
    import { defineProps, computed } from 'vue'
    
    const props = defineProps({
        showProduct: Boolean,
    });
    
    const hidePDP = computed( () => {       
        return props.showProduct = false
    });
</script>

I get these errors and I'm guessing props even when they've been a ref() value still don't like you mutating them.

60:16  error  Unexpected mutation of "showProduct" prop    vue/no-mutating-props
60:16  error  Unexpected side effect in computed function

However I haven't been able to successfully find a way to update the Boolean value in the child (reverse the Boolean value) so the parent can remove the ChildComponent element from the render when a close button is clicked in the Child Component itself.

I hope that makes sense, I've seen a few questions that talk about getting help for the reverse of sending prop data to the child from the parent (which I've already got working) like props value not sending the updated value from parent to child component in vue and Creating local copy of passed props in child component in vue.js?, but not an exact answer to the above.


Solution

  • Just use v-model:

    Playground

    
    <script setup>
      import { ref } from 'vue'
      import ChildComponent from './Child.vue'
      
      let showProduct = ref(false)
      
    </script>
    
    <template>
      <button @click="showProduct = true">view product</button>
      <ChildComponent v-if="showProduct" v-model:show="showProduct" />
    </template>
    

    Child:

    <script setup>
        const show = defineModel('show');
    </script>
    
    <template>
      <div class="close" @click="show = false">X</div>
    </template>
    

    I would even prefer to move v-if into the child:

    Playground

    Or even move the show button into the child... so no any v-model is needed.