Unsubscribing from a handle without an infinite loop


#1

I use the following to query a server-side list of transit stops which returns sorted based on proximity to the user’s position:

getMeteorData() {
  var data = {}
  var options = {}
  options.limit = this.state.limit
  var position = {}
  if(Meteor.settings && Meteor.settings.public && Meteor.settings.public.defaultPosition)
    position = Meteor.settings.public.defaultPosition
  if(Meteor.isClient)
    position = Geolocation.latLng()
  options.position = position
  data.handle = Meteor.subscribe("stops", options)
  data.ready = data.handle.ready()
  data.stops = Stops.find().fetch().map(function(stop) {
    stop.id = stop._id
    return stop
  })
  return data
},

This sets a default position so the map rendering starts out sensibly, then snaps to the user’s current position when or if it arrives. Unfortunately, the old subscription is still active, meaning the user gets their nearest stops along with those of the previous position.

What I’d like to do is stop the old subscription handle when the position changes. Unfortunately, when I do this in getMeteorData it triggers an infinite loop and nothing updates. Maybe this is because I’m storing the handle in data, but I’ve also tried:

  handle: null,
  getMeteorData() {
    this.handle = Meteor.subscribe(...)
  },

And that, too, triggers an infinite loop where nothing renders. Interestingly enough, I do get one server-side render of the data. The problem seems to be on subsequent invalidations/rerenders, and I can’t think of how to accomplish this without triggering a loop.

Thanks.


#2

getMeteorData is there to re-render every time data there changes from DB etc
handle your logic elsewhere. For example default values can be set as component is mounting.

I doubt that simple

getMeteorData() {
    this.handle = Meteor.subscribe("something")
 }

would run in infinite loop unless you are feeding reactive variable to it an changing 10x per second.


#3

OK, I’ve figured it out, it isn’t related to subscriptions at all.
Rather, it’s:

      data.position = Geolocation.latLng()

If I comment that out, rerenders drop off to much more reasonable levels.

The position is being calculated on a non-moving tablet without GPS, and
is equal between calls. I’m guessing that creating a new position in
getMeteorData() causes it to appear as a new dependency and reruns?
Where should I be calling this if I want it to reactively change when
the position updates and need to call getMeteorData, but don’t want the
simple act of calling it to cause another rerun?


#4

@ndarilek I can’t tell if that part is just state stored in client memory but if you need to control re-renders you may want to use something like Redux to keep track of it. This makes the mental model of when and how often it’s re-rendered fairly easy.

Then you can still use the mixin for subscriptions and collections like normal.

Redux: https://blog.andyet.com/2015/08/06/what-the-flux-lets-redux
Redux/flux in Meteor Is flux worth using. When is it good or bad to use