At Feathr, our main front-end application is built on Marionette and BackboneJS. Since a lot of our application is CRUD, we have a ton of Backbone Models and Collections in our application. The basis of our application revolves around these Models and Collections, so all of our technical decisions must keep this in mind. When introducing a new piece of technology, it either has to play well with Backbone or we would need to rewrite all of these models/collections to cater to the new piece of technology. Most companies, regardless of size, don’t have ample resources to do heavy rewrites to cater to using to new technologies. I try to avoid prescribing total rewrites unless completely necessary, and instead recommend incremental change towards your goal.

I recently started writing a new feature in our application using React, and one thing I learned early on is that it’s hard to keep a view built with React Components in sync with your Backbone Models and Collections.

A Quick Refresher — Using Backbone With Marionette

In a traditional Backbone/Marionette application, Marionette Views listen for events that are propagated from models and collections. Generally, your View has one specific model and/or collection passed into it, and you listen for events on those objects to trigger render cycles. For instance:

This view takes in a model that has a height and width property. To keep your view in-sync with your model, you specifically list change:width and change:height as two events you are listening to on the model passed in. When those change, it re-renders the entire view.

Using Backbone with React

In the following example, I recreate the view from above, but use a React functional component to render the same view.

One issue that immediately becomes apparent is that the view will not re-render when the model propagates events. However, this view is a functional component and probably doesn’t need to care about re-rendering — the parent component would probably manage that.

What if this component needed to re-render based on changes on the model? Well, that would look something like this:

There are a few issues with this approach. One of the biggest ones is that since React Components can’t listenTo Backbone events like a Marionette View can, we are attaching events on the model. This breaks one of the core concepts of React, where your view shouldn’t be mutating your state.

Another issue is that we need to explicitly opt-in to every single event that may influence the render of this view. In the example above, it’s pretty straightforward, but in a complicated example it may be harder to keep up.

Trying to use Redux to Glue Together Backbone and React

A lot of teams/projects have adopted Redux as their preferred method of keeping their React view in sync with the state. I myself have used the Flux pattern on a few projects and prefer to use it when I can. That being said, using Redux with Backbone just doesn’t feel right.

For one, Backbone models are mutable. This really hurts when you decorate your component with the connect function provided by react-redux . You can’t simply return a Backbone model from mapStateToProps , like so:

If you were to set height or width on the model, the model would still be the same reference in memory. This is actually very important for traditional Backbone applications, because any events you have on that model need to persist. It would be a very expensive transaction if Backbone created a new instance of the model every time it were mutated, like immutable does. What problem this presents is that your view will not re-render correctly because when the view decides if it needs to re-render, it will see that previousState.model === state.model and not re-render appropriately.

You could pass in just the needed attributes in your mapStateToProps , but that means every time you add something to your model you’ll need to add it to this function. That can get a bit cumbersome to maintain over time. It also opens the door to having parts of your state that you shouldn’t be mapping to state, which will cause funky and hard to debug bugs in the future.

Enter MobX, the Solution to Our Problems

After having these issues around React, Redux and Backbone, I started exploring new options. One solution I explored was mobx , and only after a bit of tinkering it seemed to work perfectly for our use case!

In a traditional mobx powered React application, you have state and views that look like this:

If you pass in an instance of Rectangle in the props to RectangleMobx , it will intelligently update when either height or width change.

I started thinking “maybe I can use mobx to keep my React views in-sync with my Backbone models?”. The answer is, yes! Take a look at this example:

Here I’ve wrapped the model’s attributes with observable , which transforms the attributes into an observable object. Now I just need to dereference an attribute in a render function, and the component will re-render when the model changes!

The only thing of note here is that I’m referring to the attributes through rectangle.attributes.height instead of rectangle.get('height') . I’m not sure yet if rectangle.get('height') dereferences the attribute in a way that would cause the component to re-render, but it’s worth experimenting on.

Now you have an easy way of migrating to React even in an application that already depends heavily on Backbone! As always, let me know what you think in the comments! 😃