Zach
Zach

Reputation: 1331

Meteor - how to tell what's causing a template to re-render?

I have a Meteor template that is rerendering about ~6 times in the first few seconds, making a spinner (spin.js) stutter.

I can't tell why the template itself would be rerendering, and adding {{#isolate}} and/or {{#constant}} tags isn't helping.

My question: Is there a programmatic way to determine what event or reactive data source is triggering a given rerendering?

Upvotes: 3

Views: 277

Answers (1)

nathan-m
nathan-m

Reputation: 8865

So to figure out which Template Helper is being invalidated, you've got a few options:

  1. first is to just edit the source for Meteor packages/deps/deps.js and just add a stack trace to the invalidate function.

    You can get a stack trace with something like try{throw new Error('');}catch(ex){ console.log(ex.stack);}

  2. Proxy Deps.Computation.prototype.invalidate, similar to (1)

    var oldInvalidate = Deps.Computation.prototype.invalidate;
    Deps.Computation.prototype.invalidate = function(){
      try{throw new Error('');}catch(ex){ console.log(ex.stack);}
      return oldInvalidate.apply(this,arguments);
    }
    
  3. Create a reactive function wrapper, which prints a log message when invalidated

    You can do something akin to the isolate-value package - but add a logging statement (and remove the value isolation)

    (disclaimer: haven't fully tested this code, but you can get the general idea)

      logInvalidation = (stmt, fn) ->
        value = null
        outerComputation = Deps.currentComputation
        dep = new Deps.Dependency()
        c = Deps.autorun (c) -> 
          # kill this computation if the computation wrapping the handler is stopped
          if outerComputation?.stopped
            c.stop()
            return
          unless c.firstRun
            # a dependency from `fn` was changed (hence this computation was invalidated)
            # so, invalidate anything that depends on `dep`
            console.log("Helper invalidated #{stmt}")
            dep.changed()
          else
            # attach dependencies in `fn`, and pass result to `value`
            value = fn()
          return
        dep.depend()
        return value
    

    And wrap your suspected helpers like so:

      Template.myTemplate.helpers
        myHelper: ()->
          return logInvalidation 'myHelper invalidated!', ()->
            return Session.get("myValue")
    

Upvotes: 4

Related Questions