meteor-vue / vue-meteor-tracker

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

Reactivity is hyper #67

Open jamgold opened 4 years ago

jamgold commented 4 years ago

I love the Meteor integration, but have difficulties understanding reactivity and it's implementation.

Apparently meteor functions are running many times, even before the component is created or mounted? Here is a meteor block I have in a component. It's subscribing to items publication based on a computed query. $subscribe and itemsCursor is triggered many times, even before the component is ready or meteor is active, and I do not understand why.

created(){
 const component = this;
 component.$startMeteor();
},
meteor: {
  $subscribe: {
    items: function(){
      const component = this;
      console.log(`$subscribe mounted=${component._isMounted}`, component.query);
      return [ component.query , {limit:9} ];
    }
  },
  itemsCursor () {
    const component = this;
    const isMounted = component._isMounted;
    const meteorActive = component._meteorActive;
    // this runs several times, even before component is created or mounted
    console.log(`itemsCursor found ${Items.find().count()} items mounted=${isMounted} meteor active=${meteorActive}`);
    return Items.find({}, {
      sort: {created: -1}
    });
  },
},
red-meadow commented 4 years ago

How many times exactly? Normally, it is triggered 2 times - still too many. Check this issue #49. And regarding $startMeteor(), it has effect only if you deactivates Meteor with $stopMeteor() first or use $lazy option.

jamgold commented 4 years ago

Well, it seems to be tied to the VUE lifecycle hooks. I was able to cut down on the number by no longer using dynamic layouts

<component :is="layout">
    <router-view :layout.sync="layout"/>
 </component>

but it still calls the $subscription at least twice, as well as the collection results, even before the component has been created

red-meadow commented 4 years ago

it still calls the $subscription at least twice

Right, that was reported in #49. The source of an issue is how integration with Tracker is implemented, you can't avoid it for now unfortunately. I've created 2 PRs with possible solutions but they haven't been reviewed yet.

even before the component has been created

This is by design, Meteor data is initialized inside beforeCreate.

jamgold commented 4 years ago

@red-meadow thanks for responding, and point me to #49 (again). I am working around it by using Tracker.autorun and Meteor.subscribe for now

jamgold commented 4 years ago

The other issue I noticed with this package is that subscriptions with limit and skip just grow the collection on the client. If I subscribe to a publication with 1000 entries with limit 10 and skip 0, as I skip through it, the client has 10, 20, 30 entries in the collection, and that is not right

red-meadow commented 4 years ago

Do you mean that limit and skip values are dynamic? I'm not familiar with that part of the code but as far as I remember arguments for $subscribe are passed directly to Meteor.subscribe, with no processing. Are you sure that this is a package issue? Does it work correctly with just Meteor.subscribe inside beforeCreate?

jamgold commented 4 years ago

Yes, it works correctly with Meteor.subscribe. When I use

meteor:{
 $subscribe:{
  publication(){
   return [ {}, {skip: this.skip, limit: this.limit} ]
  }
}

where skip and limit are defined in the component, then it is hit or miss

red-meadow commented 4 years ago

I tried to reproduce your issue and also encountered a strange behavior. I used <input> element with v-model to manipulate this.skip and this.limit values but forgot to convert them to numbers before passing to subscribe and got server errors. The problem was solved by adding the .number modifier to v-model. I think you may have the same issue. Here is a working example: https://github.com/red-meadow/vue-meteor-tracker-issue-67.

red-meadow commented 4 years ago

Actually this strange behavior in case of invalid arguments passed to subscribe is caused by another issue #22 .

shankscoder commented 4 years ago

I know this isn't directly related to this issue, but if you're looking for a way to more efficiently access your Meteor methods and publications in Vue this might help.

I was able to get around using meteor tracker directly using Grapher (https://github.com/cult-of-coders/grapher) and this package: https://github.com/Herteby/grapher-vue. To directly call custom methods I used this library: https://github.com/GoldenPassport/vue-meteor-reactive-promise-calls in async/await method functions.

Grapher lets you dynamically and efficiently query against your db using a GraphQL-like syntax, the grapher-vue package gives you a property in your Vue component to construct your query from your client extremely quickly and efficiently, and return the values to the component as either a method (one-time) or a publication (reactive). You define a firewall to limit fields, permissions, etc to restrict access to your query interfaces when configuring your collections access initially.

This also made it super easy to do pagination, real-time searches, etc.

The only place where I'm using tracker directly is in Vuex to subscribe to updates to the user's account profile to allow for tracking account status, etc.

I hope this helps. Let me know if you have any issues using this setup in your implementation. Happy to clarify if you have any issues.