React without Redux
How we moved from Backbone to React without rewriting
Wednesday, Jul 26th, 2017
Mixmax is a communications platform that brings professional communication & email into the 21st century.
Over time, however, Mixmax's scope has grown significantly. In addition to writing rich emails with our advanced email editor, our users can now see team-wide insights into their communications, create sophisticated email campaigns using Sequences, and share availability using their Mixmax calendar.
As we built these features, we noticed some shortcomings in Backbone:
- Rerendering Backbone views could cause cursor focus and scroll position to be lost because our Backbone
renderfunctions fully replaced the
innerHTMLof the views' root elements.
- Rerendering Backbone views would often result in unnecessary work being done (relative to something like the virtual DOM), which meant that users saw more spinners and glitchineess than was necessary when using Mixmax.
- Configuring Backbone views to rerender when data changed involved writing code that was relatively verbose and complex.
These issues' significance swelled over time. We recently reached a tipping point when implementing double-click-to-rename became a multi-day project and thus decided set out to solve these issues.
We initially identified three classes of solutions.
Use Backbone differently
Some of our issues were resolvable without changing frameworks. For example, in some cases, to avoid losing scroll position, we could update only a specific part of the UI using view functions rather than rerendering entire, top-level views using Backbone Views'
render functions. Unfortunately, this effectively meant writing a custom virtual DOM implementation using jQuery in every Backbone view that needed this sort of updating, which seemed extremely costly and complex. We trialed this approach in one view and proved this costliness to ourselves, then ruled it out.
Keep Backbone's data management and replace its rendering
We envisioned an intermediate solution where we would continue using Backbone and our Meteor-like publications libraries (1, 2) that we had integrated with Backbone to manage our client-side data, but replace Backbone's UI rendering. This solution would allow us to continue using all of the Backbone models and collections we had already written, therefore lowering the cost of adopting a new framework.
Replace Backbone entirely
Last, we considered replacing Backbone altogether. The only advantage of this solution we imagined was that we might somehow benefit from being all-in on a new framework. The downside of this approach was that replacing our usage of Backbone entirely would be very expensive in terms of engineering time.
We didn't discover any reasons for this cost being worthwhile in our investigation of frameworks, so we decided on the intermediate solution: replacing Backbone's rendering layer.
Selecting a framework
We based our investigation into view framworks on a number of requirements and considerations. Given our choice to replace only Backbone's view layer, we required that our new framework interoperate with Backbone models and collections, not require us to rewrite any existing views to minimize adoption cost, and be mature/well-backed for reliability. Additionally we hoped that the new framework would increase our speed of development, be easy-to-use by designers (ie markup-like), enable us to easily write modular code, and be compatible with our existing client-side routing.
We eliminated Vue because we felt its directives would be less intuitive to designers than JSX or Handlebars-like syntax and because it lacked any apparent, significant advantages over React while being much less mature than React.
We liked Angular for being being widely used in production, but eliminated it based on there not being a straightforward way to integrate it with Backbone and it having a steep learning curve.
We liked Ractive because it shared many of the benefits React offered while having Handlebars-like templating syntax, which we liked and knew well. Unfortunately, Ractive didn't seem to be widely used in production (1, 2) and seemed to be maintained by a small handful of people. We noticed that the project's GitHub issues were not resolved quickly and that there were
TODOs in the project's docs, which concerned us.
Mixmax + React
We've developed a number of React patterns since beginning to use the framework.
To integrate React components into our existing Backbone view hierarchies, we've been using
ReactDOM.render within Backbone views'
We've been using MongoDB's open-source
connect-backbone-to-react library to create components (using a higher-order component from that library) that update when our Backbone models and collections change. Doing so has made integrating Backbone with React straightforward and fun!
We've also been creating "container" and "presenter" components as explained by Dan Abramov. Dividing our React components like this has allowed us to achieve the sort of "view" and "controller" separation we enjoyed with Handlebars templates and Backbone Views.
In our few weeks with React, we've written two Mixmax Dashboard sections in it: Meeting Types and Rules. We're already loving how easy it is to build reusable UI components and how our struggles with Backbone, like maintaining scroll position across renders, are long-gone.
Shoot us a message if you're interested in writing React with us :)