meteor-vue / vue-meteor-tracker

Use Meteor Tracker reactivity inside Vue components
90 stars 20 forks source link

Watchers breaking computed property #38

Closed paulschwoerer closed 5 years ago

paulschwoerer commented 6 years ago

I might have found an issue when using watchers on computed properties including meteor data. To illustrate, take the following example (using the VueMeteor demo app):

In the Notes.vue Component we'll be adding a watcher for the firstNote() computed property.

watch: {
  firstNote(val) {
    console.log(val)
  }
}

After adding the watcher, the computed property will not compute, as this.notes is undefined in the computed property for some reason.

The same can be observed for another another example:

computed: {
  notesCount() {
    return this.notes ? this.notes.length : -1;
  }
}

This computed property will compute just fine, but as soon as we add a watcher to observe changes in the item count, it will break, meaning it will not recompute and always show -1.

watch: {
  notesCount(value) {
    console.log(value)
  }
}

This behavior can be fixed with the following:

computed: {
  notesCount() {
    return this.$subReady.notes ? this.notes.length : -1;
  }
}

Using this computed property, the code will behave as expected, updating the count of items and printing it to the console through the watcher whenever it changes. Maybe this is something to look into as I think the first example should behave in the same way as the latter.

This issue might be related to #34.

Reproducing example repo https://github.com/paulschwoerer/meteor-vue-tracker-watcher-error-example

Cheers!

thearabbit commented 6 years ago

+1, I can't use watch

  meteor: {
    $subscribe: {
      ['app.company']: [],
    },
    company() {
      return Company.findOne()
    },
  },
watch:{
   company:{
      handler(val){
           // don't work
      },
      immediate: true,
   }
}
hluz commented 6 years ago

Maybe try this?

meteor: {
    $subscribe: {
      ['app.company']: [],
    },
    company() {
      return Company.findOne() || {}
    },
  },
watch:{
   company:{
      handler(val){
           // don't work
      },
      immediate: true,
   }
}
dylanalizon commented 6 years ago

Maybe we have to use observeChanges ? But how ? Someone has an idea please ?

thearabbit commented 6 years ago

I will try soon

mathieustan commented 6 years ago

I encounter the same problem. It seems like when watcher remove computed reactivity. If I comment a watch, which are linked to a Meteor data, computed works fine.

Exemple with watch :

computed: { 
    notes() {
        return this.$autorun(() => Notes.find({}).fetch());
    }, 
    notesCount() {
        console.log(this.notes); // always undefined
        return this.notes.length;
    },
},
watch: {
    notesCount: {
        handler(count) {
            console.log(count); // undefined
        },
        immediate: true,
    }
}

Exemple WITHOUT watch :

computed: { 
    notes() {
        return this.$autorun(() => Notes.find({}).fetch());
    }, 
    notesCount() {
        console.log(this.notes.length); // return a number, works fine & reactive
        return this.notes.length;
    },
},
watch: {
    /*notesCount: {
        handler(count) {
            console.log(count); // undefined
        },
        immediate: true,
    }*/
}
mathieustan commented 5 years ago

I investigate this issue. It seems like, in _computedWatchers, our computed property looses its deps.

With just a computed property :

capture d ecran 2018-09-21 a 14 54 16

When there is a watch on this computed property:

capture d ecran 2018-09-21 a 14 53 52

@Akryum any idea why deps disappear when we introduce a watch which is related to a data from $meteor.data ?

vbgm commented 5 years ago

+1

Akryum commented 5 years ago

Duplicate of #34