Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Vue.js provide/inject reactive

Tags:

vue.js

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?

like image 509
John Moore Avatar asked Feb 26 '20 14:02

John Moore


People also ask

How do you make provide inject reactive?

Using the data() function The first technique is to make the object reactive by initializing it in our data() function: export default { provide() { return { reactive: this. reactive }; }, data() { return { reactive: { value: "Hello there" } }; } }; Any object that is initialized here will be made reactive by Vue.

When to Use provide and inject in Vue?

We also need to use the provide() notation if we are giving any per-instance state - i.e. where the data is coming from the data() function. Now that we've provided data, it can be accessed in any child component at any level by using the inject function.


2 Answers

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.

like image 151
Mikhail Semikolenov Avatar answered Sep 24 '22 22:09

Mikhail Semikolenov


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.

like image 23
John Moore Avatar answered Sep 26 '22 22:09

John Moore