A History of Data Management in Meteor

It’s funny, the way we subscribe to data in Meteor has changed so much over time. From the beginnings with Iron Router and waitOn calls, to template level subscriptions and now with React and Angular in the mix, the confusion is even greater! We have tutorials doing this in every different flavor…and that is the PROBLEM.

What are subscriptions?

Subscriptions are a way to send data to the client via WebSockets. In Meteor this tunnel is communicated across the “wire” via DDP. DDP, the Distributed Data Protocol, is a simple protocol for fetching structured data from a server and receiving live updates when that data changes.

waitOn, subscriptions: Iron Router — The Dark Ages

When Meteor first hit the scene, data management was up in the air. It wasn’t until Chris Mather’s package Iron Router hit the scene that Meteor developers had a clear place to not only manage Routing but subscriptions and layout rendering as well.

Router.route('/post/:_id', {
// this template will be rendered until the subscriptions are ready
loadingTemplate: 'loading',

waitOn: function () {
// return one handle, a function, or an array
return Meteor.subscribe('post', this.params._id);
},

action: function () {
this.render('myTemplate');
}
});

Blaze Template Level Subscriptions — The Silver Age

Moving past Iron Router, MDG stepped gave us a solution in Meteor v1.0.4….The Template Level Subscription. This solution is beautiful. It allows Blaze users to utilize Template instances to subscribe to data and functions exactly like Meteor.subscribe, but stops the subscription when the template is destroyed.

Template.exampleComponentContainer.onCreated(function () {
const template = this;
template.autorun(()=> {
template.subscribe(‘exampleSubscription’);
});
});
Template.exampleComponent.helpers({
exampleData() {
return ExampleData.findOne({_id: ‘1’}, {fields: {‘name’: 1}});
}
});
// HTML// Container Component
<template name=”exampleComponentContainer”>
{{#if Template.subscriptionsReady}}
{{> Template.contentBlock}}
{{else}}
{{> loading }}
{{/if}}
</template>
// Example Component
<template name=”exampleComponent”>
<h1>{{exampleData.name}}</h1>
</template>
// Page Component
<template name=”examplePage”>
{{#exampleComponentContainer}}
{{> exampleComponent}}
{{/exampleComponentContainer}}
</template>

Angular Controllers Subscriptions — The Golden Age

Starting with Meteor 1.2, users had first class support for AngularJS. This was another great burst of new methods of data fetching. The interesting thing here is that even with angular, the move to a more component data fetching model remained true. In Meteor Angular, the controller for your component is the perfect place to subscribe to data.

angular.module(‘simple-todos’).controller(‘TodosListCtrl’, [‘$scope’, ‘$meteor’, function ($scope, $meteor) {    $scope.$meteorSubscribe(‘tasks’); 
$scope.tasks = $meteor.collection(function() {
return Tasks.find($scope.getReactively(‘query’), {sort:{createdAt: -1}}) });
$scope.addTask = function (newTask) {
$meteor.call(‘addTask’, newTask);
};
};

React getMeteorData — The Future

Another framework given to us in Meteor 1.2. was React. The way we subscribe to data in React is similar to the methods described above. Meteor subscriptions in React are channeled through a mixin called ReactMeteorData.

// COMPONENT CONTAINERExampleContainer = class ExampleContainer extends React.Component {
constructor() {
super();
this.onBtnClick = this.onBtnClick.bind(this);
}
getMeteorData() {
const handle = Meteor.subscribe('exampleSubscription');
const isReady = handle.ready()
const exampleData = Example.findOne();
return {handle, isReady, exampleData};
}

onBtnClick() {
alert("You clicked me!");
}
render() {
if (!this.data.isReady} {
return <Loading/>;
}
return (
<ExampleComponent
onBtnClick={this.onBtnClick}
item={this.data.exampleData}/>
)
}
}
reactMixin(ExampleContainer.prototype, ReactMeteorData);// STATELESS COMPONENT FUNCTIONExampleComponent = ({name, description, onBtnClick}) => {
return (
<div>
<h1>{name}</h1>
<p>{description}</p>
<button onClick={onBtnClick}>Click Me!</button>
</div>
)
}

Conclusion

As you can see! We’ve come a long way! My point in all this is in trust your components. You can see in the beginning we were relying on a layer in the router that was very hard to reason about and became UNPREDICTABLE as the app scaled. When dealing with data management, we should always understand where our data comes from and how it flows. This is why in each of these examples, we put the data fetching responsibility on the components. In each form, we rely on a container component to fetch data then pass this data to our presentational components. Though each of the frameworks may have a different syntax, one theme remained true: it’s hard to manage the starting and stopping of subscriptions yourself. This is why Meteor created automatic unsubscribes when our components onDestroyed, $destroy, and unmount.

Software Engineer at Workpop, Inc.

Software Engineer at Workpop, Inc.