Search code examples
meteormeteor-tracker

Are stop-returning functions still stopped when inside nested functions?


In addition, the following functions which return an object with a stop method, if called from a reactive computation, are stopped when the computation is rerun or stopped:

Tracker.autorun (nested) Meteor.subscribe observe() and observeChanges() on cursors

This means that the observe stops here:

Tracker.autorun ->
  cursor.observe()

But what about here?

Tracker.autorun ->
  Tracker.nonReactive ->
    cursor.observe()

Solution

  • When a MiniMongo reactive handle (find(), observe(), etc.) is created in a reactive computation, MiniMongo will detect it and attach a listener to the computation's onInvalidate that will stop the handle when the computation is invalidated (or stopped).

    It does not matter whether this is done directly in the autorun callback or in a function that is called from the callback it, as long as it is done synchronously (i.e, while in the context of the same computation).

    There is one notable exception: a non-reactive callback.

    A Tracker.nonreactive callback is fired within a non-reactive context, so the current computation is set to null and Tracker.active is set to false. Under those conditions, MiniMongo will not attach the aforementioned listener and the change observer will not be stopped automatically.

    You can stop it manually, though:

    const MyCollection = new Mongo.Collection(null);
    const cursor1 = MyCollection.find({foo: 'bar'});
    const cursor2 = MyCollection.find({foo: 'baz'});
    
    let observeCallback = {
      added(doc) {
        console.log('added', doc);
      }
    };
    
    
    let handle = Tracker.autorun(function(c) { // c is the computation object
      cursor1.observe(observeCallback); // will be automatically stopped
    
      Tracker.nonreactive(function() {
        let observer = cursor2.observe(observeCallback);
        c.onStop(function() {
          observer.stop(); // explicitly stops the observer
        })
    
      });
    
    });
    
    MyCollection.insert({foo: 'bar'});
    MyCollection.insert({foo: 'baz'});
    
    handle.stop();