Meteor Deep Dive – Reactive Programming With Tracker

Meteor Deep Dive – Reactive Programming With Tracker

Introduction

As a Meteor developer, I believe that everyone who has worked with Meteor all had experience with Tracker, or at least used it through some kinds of interfaces like getMeteordata or createContainer which come with the react-meteor-data package.

However, not all people know how Tracker works its magic. In this post, I’m going to dig into every facet of this case as well as bring to you a little bit of background knowledge.

What Is Tracker?

Tracker is a Meteor’s core package, it is small but incredibly powerful library for transparent reactive programming in Meteor.

Using Tracker you have much of the power of Functional Reactive Programming FRP system without following FRP’s principles when implementing your application. Combined with Tracker-aware libraries, like Session/ReactiveVar/ReactiveDict, this lets you build complex event-driven programs without writing a lot of boilerplate event-handling code.

What Make It Great?

In a nutshell, it is reactivity. In my opinion, it is the strongest aspect of Meteor. Tracker helps us make our system work reactively both on client and server with ease. We do not have to learn any extra stuffs about reactive programming or functional programming to get started.

Just read the Tracker api and do the work then the magic happens. Or even some Meteor-novice who do not know a thing about Tracker, their code still work reactively. Do you know what am I talking about? It is good old Blaze (I say it’s old because I already moved to React for all new projects).

Blaze’s helpers are reactive natively because they use Tracker inside, if you put inside them a reactive data source then whenever that source changes those helpers will be recomputed and you get new data on the screen.

Let’s read some code and behold what I am talking about, if you are already familiar with Tracker, skip this part and move to the next section to inspect the magic.

// Set up the reactive code const counter1 = new ReactiveVar(0); const counter2 = new ReactiveVar(0); const observeCounter = function() {   Tracker.autorun(function() {     const text = `Counter1 is now: ${counter1.get()}`;     console.warn(text);   });   console.warn(`Counter2 is now: ${counter2.get()}`); }; const computation = Tracker.autorun(observeCounter); /* Message on the console: Counter1 is now: 0 Counter2 is now: 0 */ // and now change the counter1's value counter1.set(1); /* Message on the console: Counter1 is now: 1 */ counter2.set(3); /* Message on the console: Counter1 is now: 1 Counter2 is now: 3 */ counter1.set(7); /* Message on the console: Counter1 is now: 7 */ 

In reality, it happens as shown below:

Click here to see

How Does Tracker Work?

Basically Tracker is a simple interface that lets reactive data sources (like counter in the example above) talk to reactive data consumers (the observeCounter function). Below is the flow of Tracker (I ignore some good parts to make it as simple as possible)

Call Tracker.autorun with function F

If inside F, there is a reactive data source named R, then that source will add F to its dependence list

Then whenever the value of R changes, R will retrieve all its dependence from the dependence list and run them.

Everything is easier said than done. So, let’s take a look at the code:

const counter = new ReactiveVar(1);   const f = function() {     console.log(counter.get());   };   Tracker.autorun(f); 

In the above code: counter is our reactive data source. It raises a question is that how can it know what function used inside to add that function as its dependence?

This is where the Meteor team does their trick to make this flow transparent. In fact, Tracker is an implementation of the Observer pattern or at least an Observer-liked pattern. Observer pattern can be used to create a reactive library like Tracker.

In an traditional implementation of Observer, we can think of F as an observer and R as a subject. R must have an interface to add F as its observer and notify/run F when its value changes. Something like this:

const counter = new Source();   const f = function(val) {     console.log(val);   };   counter.addObserver(f); 

To imitate this, Tracker provides us these interface:

Tracker.autorun

Tracker.Dependency

Tracker.Dependency.prototype.depend

Tracker.Dependency.prototype.changed

Tracker.Dependency is the implementation of Subject in traditional Observer. All of reactive data source to use with Tracker use this object inside.

Let’s look at the basic implementation of ReactiveVar I use for examples above:

ReactiveVar = function (initialValue, equalsFunc) {     if (! (this instanceof ReactiveVar))       // called without `new`       return new ReactiveVar(initialValue, equalsFunc);     this.curValue = initialValue;     this.equalsFunc = equalsFunc;     this.dep = new Tracker.Dependency;   };   ReactiveVar.prototype.get = function () {     if (Tracker.active)       this.dep.depend();     return this.curValue;   };   ReactiveVar.prototype.set = function (newValue) {     var oldValue = this.curValue;     if ((this.equalsFunc || ReactiveVar._isEqual)(oldValue, newValue))       // value is same as last time       return;     this.curValue = newValue;     this.dep.changed();   }; 

So when we create a new instance of ReactiveVar, a Tracker.Dependency object will be created. This object will have two main functions: depend and changed with get call inside get and set function respectively.

This is the Tracker’s flow with more details:

Tracker.autorun will create a computation with the function (F) pass to it as the computation’s props.

READ FULL ARTICLE

To view or add a comment, sign in

More articles by Hung Vo Hoang Manh

  • Git Concepts and Architecture

    In this post, let’s examine several key concepts in Git, which will help us to better understand how it works. The…

  • 5 ways to create a logo design that kicks ass

    Ranging from Facebook’s iconic sky blue F to the golden M of McDonald’s, logos that perfectly represent brand…

    1 Comment
  • 08 Leading Web Design Trends in 2019

    Maybe most people still don’t realize that 2019 means we’re heading to the last chapter of the decade. Over the past…

  • Farewell, Year of the Dog 2018

    Time flies so fast, it’s already been five years since the day Designveloper (DSV) was established, sometimes it feels…

  • DSV’s Journey to the West

    Welcome to DSV’s Journey to the West (DSV Tây Du Ký), I must inform you before you continue to read: this is not a…

  • How to Create a Basic Plugin by jQuery

    jQuery is a quite small yet fast JavaScript library that consists of a number of extensible and durable features, and…

  • JavaScript from A to Z

    It is widely believed that one of the very first programming languages that almost every software programmer choose to…

  • 9 Must-be-obeyed Principles in Web Design

    As I said in the previous blog 6 Signs It’s Time to Give Your Website an Overhaul, in this age of data overflowed…

  • The Journey to Become a Coder and How to Survive

    Imagine me, an ordinary office girl, surely an outsider to codes, programming languages, frameworks, etc. Java? Python?…

  • Top Trending Programming Languages for 2019

    I bet every software development company, as well as freelance programmer, wants to keep up with the most emerging and…

    2 Comments

Insights from the community

Others also viewed

Explore topics