Search code examples
vue.jsvue-componentvuejs3computed-properties

Create a global computed property in a plugin in Vue 3


I'm trying to create a global computed property from within a Vue 3 plugin, so that my property can be used reactively in any component. I am using the standard Vue 3 pattern:

app.config.globalProperties.$foo = ...

This works great to let me access this.$foo from any component. However, I also want to trigger behavior when this.$foo is set. But when I try to make it a settable computed property, like this—

app.config.globalProperties.$foo = computed({
  get: () => ...
  set: () => ...
})

—it doesn't behave like a computed property: If I run this.$foo = 'bar' from a component, it simply overwrites the property, without triggering the computed setter. (Testing it on a computed without a setter, the property is also simply overwritten, where Vue would normally throw a warning.)

How can I make a global computed with a setter? Is there something I am missing here about how global properties (or computed properties in the Vue 3 composition API) are supposed to work?


Solution

  • computed() returns a ref, so its value must be accessed through the .value property. Setting $foo directly would just overwrite the reference to some new value instead of modifying the computed ref's value:

    this.$foo = 'bar'        // ❌ overwrites the computed ref
    this.$foo.value = 'bar'  // ✅ sets computed ref's value; triggers setter
    

    You likely need reactivity, and a computed ref with a getter/setter would need to use another ref for that:

    // main.js
    import { computed, ref } from 'vue'
    ⋮
    let foo = ref(123)
    app.config.globalProperties.$foo = computed({
      get: () => foo.value,
      set: value => foo.value = value,
    })
    
    // MyComponent.vue
    export default {
      methods: {
        logFoo() {
          console.log(this.$foo.value) // => 123
        },
        updateFoo() {
          this.$foo.value++
        }
      }
    }
    

    demo