John Moore
John Moore

Reputation: 7129

Making Vue.js provide/inject reactive

I am getting my head round the different ways of communicating between components and their children, grandchildren, etc., and have been taking a look at provide/inject for the first time. I can get this to work fine without being reactive (which I know is the way it is designed), but cannot get reactive behaviour using an observed object. Let's say I have a nested object structure, A > B > C, where A is the grandparent of C. I have a data property of A, 'page', changes to which I would like to observe in grandchild C. If I just provide 'page' in A and inject 'page' in C, it's not reactive (by design). I thought if I did something like this instead it might work:

In provider:

data() {
    return {
      page: null,
      obj:{currentPage:this.page}
    }
},


provide(){
     return {
       obj: this.obj
     }
  }

In child or grandchild:

inject: ['obj']

But it doesn't. If I try to use obj.currentPage in the grandchild component, it is undefined.

I'm sure this is pretty straightforward. What am I not getting?

Upvotes: 13

Views: 13663

Answers (2)

Mikhail Semikolenov
Mikhail Semikolenov

Reputation: 608

I spent a lot of time, trying to make provided/injected object reactive, and after all it was eureka! We can simply pass a function returning an object, not an object themself.

It seems as a good solution to me.

Provider:

data(){
 return {
   something: ...,
 }
}

provide(){
 return {
  getSomething: () => this.something,
 }
}

Descedant component:

inject: ['getSomething'],

computed: {
 something(){
  return this.getSomething();
 }
}

So, in descedant component, computed property this.something became reactive.

Upvotes: 33

John Moore
John Moore

Reputation: 7129

Well, as ever the answer turned out to be in a completely different place from where I was looking. There is nothing wrong with the reactivity of the 'obj' object being provided. The problem lies in the fact that the object is not being updated in the parent data object. I had obj:{currentPage:this.page} assuming that when this.page changes, the property within obj would be updated, but it isn't. So I have two options here, unless I've missed something: firstly, use a watch on page, updating the obj property; or forget about this.page altogether and make sure any updates which were hitherto done to this.page are instead done to this.obj.currentPage. It's just a case of deciding which approach is the less messy. All part of an interesting learning exercise.

Upvotes: 4

Related Questions