Template helper re-compute without getting any reactive source data!?


#1

Hello space travellers,

Please consider this code:

var reactive_source = new ReactiveVar(false);
Tracker.autorun(()=>{
    console.log("tracker recompute");
    reactive_source.set(false);
});
Template.myTemplate.helpers({
    my_helper:function(){
        console.log("recompute helper");
        reactive_source.set(false);
    }
});
Template.myTemplate.events({
    'click div'(){
        console.log('clicked');
        reactive_source.set(true);
    }
});

This is a simplified test case. To prevent misunderstanding, the template helper and the tracker are not used at the same time. I am just showing that those two behave differently, and I was not expecting this.

When using the tracker, it should seem obvious that when looking at the console, I’ll see “tracker recompute” only once, no matter how many times I click on a div…

I’d expect the template helper to do the same, but it reacts very differently: you’ll see “recompute helper” as soon as your template is created, and then you’ll see TWO “recompute helper” every time you click on a div.

It behaves exactly as if there was a reactive_source.get() somewhere in it… Now, for most people it shouldn’t be too troublesome, but it still means that every helper setting a reactive source’s value is ran twice if the new value does not equal the old one. But in my case, it blew everything up as it created a cyclic chain of re-computations.

Please, do you have any work around for this? Is it a bug or intended?


#2

Without going too deep into the reactivity chain, I am spotting that you are setting a reactive var in a template helper. I haven’t seen that much. Not sure this is the intended design. Your View part of MVC should not affect the Model part.


#3

Yes, I may not be doing things by the book… Without getting in too much details, I am working on a hack to trigger a class change for animation when a value changes.

I realize that I could do better, and will do. But I think that my concerns remain on topic as we have two reactive computations that, to my understanding, should be identical but are not.

There are as many reasons why I shouldn’t set a value in my template helper as there are for a helper to not re-compute when it sets a value.


#4

Ignoring the Tracker.autorun which only runs once and is not actually needed, the flow is like this:

  1. The initial state of reactive_source is false.
  2. The helper runs.
  3. reactive_source is set to false.
  4. The computation is not invalidated (primitive value doesn’t change).
  5. You click the button.
  6. reactive_source is set to true.
  7. The computation is invalidated (primitive value has changed).
  8. The helper re-runs.
  9. The helper sets reactive_source to false.
  10. The computation is invalidated (primitive value has changed).
  11. The helper re-runs.
  12. The helper sets reactive_source to false.
  13. The computation is not invalidated (primitive value doesn’t change).
  14. Go to 5.

#5

Thank you rob, but I am very well aware of the steps meteor takes to produce what is happening.

The right question is more of why the computation is invalidated at all? There are absolutely no getters in the helper.

The code is exactly the same (put aside the console.log text) inside the autorun and the helper… There is, to me, no reason for them to act differently.


#6

#7

There is nothing that called get… I have read through the whole file way before you posted just because I thought that set was using get itself or some sort of thing that would make the computation calling set be added to dependents, but to what I see and understand, it is not the case.

Please, could you explain better why calling .set() and NEVER calling .get() invalidates a computation? And why is it so for only Template helpers’ computations and not Tracker.autorun’s?


#8

It seems that I was not looking for answers at the right place… The computation is never invalidated. And running the scripts alone do work as intended (template helper ran only once just like the tracker autorun).

The problem was coming from the fact that the getter helper and the setter helper were on the same DOM node and it seems that Blaze feels like it needs to re-fetch all the attribute helpers which causes a rerun. I will try to have them both together and see.