Vue3 reactive components on globalProperties

Viewed 2327

In vuejs 2 it's possible to assign components to global variables on the main app instance like this...

const app = new Vue({});

Vue.use({
  install(Vue) {
    Vue.prototype.$counter = new Vue({
      data: () => ({ value: 1 }),
      methods: {
        increment() { this.value++ },
      }
    });
  }
})

app.$mount('#app');

But when I convert that to vue3 I can't access any of the properties or methods...

const app = Vue.createApp({});

app.use({
  install(app) {
    app.config.globalProperties.$counter = Vue.createApp({
      data: () => ({ value: 1 }),
      methods: {
        increment() { this.value++ }
      }
    });
  }
})

app.mount('#app');

Here is an example for vue2... https://jsfiddle.net/Lg49anzh/

And here is the vue3 version... https://jsfiddle.net/Lathvj29/

So I'm wondering if and how this is still possible in vue3 or do i need to refactor all my plugins?

I tried to keep the example as simple as possible to illustrate the problem but if you need more information just let me know.

2 Answers

Vue.createApp() creates an application instance, which is separate from the root component of the application.

A quick fix is to mount the application instance to get the root component:

import { createApp } from 'vue';

app.config.globalProperties.$counter = createApp({
  data: () => ({ value: 1 }),
  methods: {
    increment() { this.value++ }
  }
}).mount(document.createElement('div')); 

demo 1

However, a more idiomatic and simpler solution is to use a ref:

import { ref } from 'vue';

const counter = ref(1);
app.config.globalProperties.$counter = {
  value: counter,
  increment() { counter.value++ }
};

demo 2

Not an exact answer to the question but related. Here is a simple way of sharing global vars between components.

In my main app file I added the variable $navigationProps to global scrope:

let app=createApp(App)
app.config.globalProperties.$navigationProps = {mobileMenuClosed: false, closeIconHidden:false };
app.use(router)
app.mount('#app')

Then in any component where I needed that $navigationProps to work with 2 way binding:

<script>
import { defineComponent, getCurrentInstance } from "vue";

export default defineComponent({
  data: () => ({
    navigationProps:
      getCurrentInstance().appContext.config.globalProperties.$navigationProps,
  }),
  methods: {
    toggleMobileMenu(event) {
      this.navigationProps.mobileMenuClosed =
        !this.navigationProps.mobileMenuClosed;
    },

    hideMobileMenu(event) {
      this.navigationProps.mobileMenuClosed = true;
    },
  },

Worked like a charm for me.

Related