How do I make Vue 2 Provide / Inject API reactive?

Viewed 9113

I set up my code as follows, and I was able to update checkout_info in App.vue from the setter in SomeComponent.vue, but the getter in SomeComponent.vue is not reactive.

// App.vue
export default {
    provide() {
        return {
            checkout_info: this.checkout_info,
            updateCheckoutInfo: this.updateCheckoutInfo
        }
    },
    data() {
        return {
            checkout_info: {},
        }
    },
    methods: {
        updateCheckoutInfo(key, value) {
            this.checkout_info[key] = value
        }
    }
}
// SomeComponent.vue
export default {
    inject: ['checkout_info', 'updateCheckoutInfo']
    computed: {
        deliveryAddress: {
            get() { return this.checkout_info.delivery_address }, // <---- Not reactive??
            set(value) { return this.updateCheckoutInfo('delivery_address', value) }
        }
    }
}
3 Answers

I found the answer after many hours of searching. You have to use Object.defineProperty to make it reactive. I'm not sure if this is the best approach, but this is a working example.

export default {
    data() {
        return {
            checkout_info: {},
        }
    },
    provide() {
        const appData = {}

        Object.defineProperty(appData, "checkout_info", {
            enumerable: true,
            get: () => this.checkout_info,
        })

        return {
            updateCheckoutInfo: this.updateCheckoutInfo,
            appData,
        }
    }
}

You can later access it via this.appData.checkout_info

This note from official documentation.

Note: the provide and inject bindings are NOT reactive. This is intentional. However, if you pass down an observed object, properties on that object do remain reactive.

I think this is the answer to your question.

source: https://v2.vuejs.org/v2/api/#provide-inject

I would put the values in an object:

var Provider = {
  provide: {
    my_data: this.my_data
  },
  data(){
    const my_data = {
      foo: '1',
      fuu: '2'
    };
    return {
      my_data;
    }
  }
}
var Child = {
  inject: ['my_data'],
  data(){
   console.log(my_data.foo);
   return {};
  },
}

When are object properties they are reactive. I don't know if this is the correct solution but it works in my case.

Related