Reactive Stores with React

Last time, we talked about how to implement data stores in our React application. In this article, we will go over how to make a data store reactive and have it sync with a Mongo database.

One of the advantages of using a data store is the separation of concerns between the view and business logic about how to update data. The view shouldn’t care where the data comes from or how to update the data – only that it should display some prop and dispatch an event to execute.

Updating Mongo

From our previous article, we had a set of events that we could dispatch that would increment and reset a button click counter. Our goal for this article is to extend the work we did in the last article and sync the button click counter among all the clients connected to our application.

Let’s create a Mongo collection and we’ll make sure there is always a document in that collection for us to use:

Clicks = new Mongo.Collection('clicks');

if (Meteor.isServer) {
  var click = Clicks.findOne({});
  
  if (click == null) {
    Clicks.insert({
      total: 0
    });
  }
}

 

Next, let’s update the collection whenever the events in our data store are called:

 

ClickStore = Reflux.createStore({
  listenables: [ClickActions],
  init: function () {
    this._click = { total: 0 };
  },

  increment: function () {
    this._click.total++;
    Clicks.update(this._click._id, {
      $inc: {
        total: 1
      }
    });

    this.trigger(this.getInitialState());
  },

  reset: function () {
    this._click.total = 0;
    Clicks.update(this._click._id, {
      $set: {
        total: 0
      }
    });

    this.trigger(this.getInitialState());
  },

  getInitialState: function () {
    return {
      total: this._click.total
    }
  }
});

 

If we click the button now, and dispatch the increment event whenever we click, we won’t see our counter update on other clients that are listening to our collection. That’s because the store does not know that it should update when the Mongo collection receives new data.

Updating the Data Store

There are different approaches to this next part, but by far the simplest is to use Tracker, which MDG has worked so hard on. We can have Tracker autorun when ever there are changes to a collection that use within it. Making use of that, we can then trigger changes within the data store. We will have Tracker run within the init method of our data store:

  init: function () {
    this._click = { total: 0 };

    if (Meteor.isClient) {
      Tracker.autorun(Meteor.bindEnvironment(function (computation) {
        this._click = Clicks.findOne({});

        this.trigger(this.getInitialState());
      }.bind(this)));
    }
  },

And that’s all there is to creating a reactive data store!

You can view the full, working example on Github: CapsuleCat/ReactiveStoreExample