javascriptvue.jsvuejs2object-property

VueJS observe plugged parameter


I'm starting with VueJS 2 and I created a simple plugin which adds parameter to Vue instance.

I have problem because when I update this value my computed properties are still same.

My example plugin's code:

export default function (Vue) {
    Vue.MyProperty = "test"

    Object.defineProperties(Vue.prototype, {
        "$myProperty": {
            "get": function () {
                return Vue.MyProperty
            },

            "set": function (value) {
                Vue.MyProperty = value

                return this
            }
        }
    })
}

And my component's code

export default {
    "computed": {
        "test": function () {
            return this.$myProperty
        }
    }
}

When I changed this.$myProperty in other component my component returns vaid value (in example when I changed from "test" into "newvalue" I can see "newvalue") but computed property test is still old value ("test" in my example).

I tried to use this.$set(this, "$myProperty", value) but this still not working.

How can I use or declare this property to use it in computed or watched properties?


Solution

  • The reason the data value is not automatically updated in the computed is because the property you added to Vue, MyProperty is not an observed property. Fundamentally, Vue's reactivity works because all values added to data are converted into observed properties; under the hood they are converted into getter/setter pairs with some additional code so that when one of those properties changes, Vue knows to propagate the changes to all the things that depend on it's value.

    The code in the question, however, just adds a normal property to the Vue object. You can change it, but it's not reactive.

    That said, it's relatively easy to make it reactive. I cover how to do this in the comments to my answer here. Basically, instead of adding your property to Vue, just create a new Vue object (which has very low overhead) and make the property you want to be reactive a property of that Vue. Here is a working example.

    console.clear()
    
    function MyPlugin(Vue) {
      let store = new Vue({data:{MyProperty: "some value"}})
    
        Object.defineProperties(Vue.prototype, {
            "$myProperty": {
                "get": function () {
                    return store.MyProperty
                },
    
                "set": function (value) {
                    store.MyProperty = value
    
                    return this
                }
            }
        })
    }
    
    Vue.use(MyPlugin)
    
    const MyComponent = {
      template:`<div>{{test}}</div>`,
        "computed": {
            "test": function () {
                return this.$myProperty
            }
        }
    }
    
    new Vue({
      el: "#app",
      components:{
        MyComponent
      }
    })
    <script src="https://unpkg.com/vue@2.4.2"></script>
    <div id="app">
      <my-component></my-component>
      <button @click="$myProperty = 'new value'">Change</button>
    </div>