Viktor Bylbas
Viktor Bylbas

Reputation: 767

Why component does not hide after change computed property in Vue 3?

I migrate from Vue 2 to Vue 3 code. And I have a problem with computed properies.

html:

<div id="cartStatePopupApp" v-if="isShow"> <!-- v-show="isShow" does not work too -->
    <button v-on:click="change()">change</button>
    <span >{{ isShow }}</span>
</div>

js:

import { createApp } from '../../lib/vue/dist/vue.esm-browser.js';

const app = createApp({
    data() {
        return {
            isShowed: true,
        };
    },

    computed: {
        isShow() {
            debugger;
            return this.isShowed;
        }
    },

    methods: {
        change() {
            this.isShowed = !this.isShowed;
        }
    }
});

app.mount('#cartStatePopupApp');

Vue devtool show as change properties:

enter image description here

but component does not hide. How fix it? Any ideas

Upvotes: 1

Views: 42

Answers (2)

Raeisi
Raeisi

Reputation: 2191

Your computed value is fine. The issue is that Vue 3 replaces the innerHTML of the mounted element, not the element itself. Consequently, doing Vue things, like v-if, will not affect it. In your case, the v-if is placed on the exact mounted element, which Vue does not process. On the contrary, Vue 2 replaces the mounted component.

The following example demonstrates it clearly:

<div id="cartStatePopupApp" v-if="false"> ...

As a rule of thumb, ignore the mounted element and do not manipulate it. However, defining class, style, or other pure HTML and CSS stuff is fine.

You can achieve the same result by template:

<div id="cartStatePopupApp">
  <template v-if="isShow">
    <button v-on:click="change">change</button>
    <span>{{ isShow }}</span>
  </template>
</div>

Live template:

const { createApp  } = Vue;
console.log('Hello world');

createApp({
  data() {
    return {
      isShowed: true,
    };
  },

  computed: {
    isShow() {
      return this.isShowed;
    },
  },

  methods: {
    change() {
      this.isShowed = !this.isShowed;
    }
  },
}).mount('#cartStatePopupApp');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>

<div id="cartStatePopupApp">
  <template v-if="isShow">
    <button v-on:click="change">change</button>
    <span>{{ isShow }}</span>
  </template>
  
  
  <button v-on:click="change">(restore)</button>
</div>

Upvotes: 0

Shoejep
Shoejep

Reputation: 4849

I don't think you can put v-if on the root element. I've provided a snippet below where it works, if you create a wrapper element.

const { createApp, ref } = Vue

const app = createApp({
    data() {
        return {
            isShowed: true,
        };
    },

    computed: {
        isShow() {
            debugger;
            return this.isShowed;
        }
    },

    methods: {
        change() {
            this.isShowed = !this.isShowed;
        }
    }
});

app.mount('#cartStatePopupApp');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>

<div id="cartStatePopupApp">
  <div v-if="isShow">
    <button v-on:click="change()">change</button>
    <span >{{ isShow }}</span>
    </div>
</div>

Upvotes: 1

Related Questions