Comparing Marionette and React

The JavaScript landscape is changing rapidly. If you’re anything like me you’ll know that trying to keep current amidst the churn can be frustrating. We can but try, however. To this end I’ve been learning about React and thinking about how it compares to another UI library I’ve used in the past: the Backbone-based library, Marionette.js.

Why React?

  1. React is relatively well-liked. In the 2016 State of JavaScript “Frameworks” survey 3044 respondents claimed to have used React before, 92% of whom claimed they would use it again. React achieved the highest satisfaction rating, Vue finishing a close second with 89%. Vue had only a fraction of React’s users, however: Only 577 respondents claimed to have used it before. Angular 2 (1092/65%), Ember (850/48%) and Angular (3391/47%) lagged significantly behind React and Vue in one or both regards.
  2. Marionette is relatively obscure. In the same survey Marionette was mentioned by just 41 respondents. No data was given for whether these respondents had used it before or would use it again. Meanwhile Backbone, upon which Marionette is based, acquired a relatively low satisfaction rating: Although a relatively high number of users (2077) claimed to have used it before, only about one-third (32%) claimed they would use it again.
  3. React is more library than framework. Unlike full-blown JavaScript frameworks such as Angular, React is mainly a view library. In this sense it it tempting to see React as a more direct replacement for Marionette, much of whose value in my opinion comes from the views it provides. In principle I tend to prefer libraries over frameworks, chiefly because the latter tend to be more prescriptive in terms of how apps should be constructed.

In summary React appears to be a pretty safe choice that should provide a natural progression from Marionette. Let’s put that to the test by creating an app. We’ll implement a simple ticking clock (featured in the React docs) doing it in both Marionette and React so we can compare.

Creating an application

When creating a JS app it’s nice to have a single object that serves as an entry point to the rest of the UI. Both Marionette and React embrace this concept: Marionette via a dedicated Application class; React via a top-level Component that serves as a parent to other, “child” components. So let’s begin implementing our ticking clock by creating a simple application.

Requirements

  • Output “The time according to {library} is:” to the page

Code

Marionette implementation

To implement the requirement in Marionette:

  1. We created a callback function (onStart) for adding a view containing the output to the DOM. This function runs when the application starts. It first creates a region for showing the view, then creates the view, then shows the view in the region.
  2. We created an instance of the Application class.
  3. We attached an event listener (“start”) to the application instance, passing it the callback function defined in #1.
  4. We started the application via the “start” method on the application instance.

React implementation

To implement the requirement in React:

  1. We created a component for adding the output to the DOM. In this case the component is a functional component but as we’ll see later it could also have been a class component.
  2. We added the output to the DOM via ReactDOM.render. This method basically just merges our component with the DOM, similar to Marionette’s region.show method in #1 above.

Analysis

We can see that React makes life a little easier for getting an app off the ground. While Marionette introduces several different concepts right off the bat (Applications, Regions and Views), React introduces just one (Component). React also appears to do things a little more automatically, e.g., no need to officially start the application or create a listener for the start event. React’s syntax also ends up being cleaner and more terse.

Character count

  • Marionette: 296
  • React: 121

Nesting views

Another essential feature of a JS view library is the ability to nest one view within another view. Nested views reflect the treelike structure of the DOM tree and help to encapsulate functionality within clearly defined modules. Both Marionette and React embrace the concept of nested views: Marionette via its dedicated LayoutView class; React via components. So let’s enhance our fledgling app to illustrate how nested views work in each case.

Requirements

  • Add a view for displaying the title
  • Add a view for displaying the clock

Code

Marionette implementation

To implement the requirements in Marionette:

  1. We added two regions to our LayoutView: one for the title, one for the clock. The LayoutView is a special type of view provided by Marionette distinctly for layout purposes.
  2. We created a callback function (onShowLayoutView) for adding views to the regions defined in the layout view. This function runs after the layout view has been added to the DOM.
  3. We attached an event listener (“show”) to the layout view, passing it the callback function defined in #2. Waiting for the parent view to be added to the DOM before attempting to add the child views ensures Marionette will not try to add the latter before the former is ready.

React implementation

To implement the requirements in React:

  1. We created two user-defined components (AppHeader and AppBody) to represent the nested views.
  2. We rendered the nested components in the parent component using the latter’s “render” method.

Analysis

React again seems to make things easier for us. Marionette introduces yet another concept (ItemView); React allows us to reuse an existing one (Component). Marionette makes us do more work (e.g., we have to manually instantiate all new objects); React does this work for us (we can simply define a component declaratively and React will create it for us). React’s syntax again ends up being cleaner and more terse.

CHARACTER COUNT

  • Marionette: 639
  • React: 252

Managing state

The concept of state as it applies to JS apps is admittedly rather new to me: With hindsight I suppose it’s just one of those things I’ve been doing with JS/jQuery/Backbone/Marionette without really thinking too much about how I’m doing it.

To be going on with let’s just define managing state as managing change. In the context of an app the source of change could be manual or automatic. For example:

  • A user enters a value in a text box (manual)
  • A timer updates a value every so often (automatic)

What these cases have in common is that something happens in the app and the app has to respond somehow. In other words, the app must undergo a change in state.

Once again let’s illustrate this by way of our app, this time by implementing the ticking behavior of the clock.

Requirements

  • Store the date so that it can be updated
  • Set a timer to update the date every second
  • Display the date (and redisplay it whenever it’s updated)
  • Clear the timer if the component is ever removed from the page

Code

Marionette implementation

To implement the requirements in Marionette:

  1. We created an ItemView to represent the clock.
  2. We created a Backbone model to store the date, passing the model into the view.
  3. We created a timer (setInterval) for updating the date and set it to update the model’s date attribute every second. We did this within view’s constructor function (initialize).
  4. We created an Underscore template for displaying the date, saving it to the view’s template property.
  5. We instructed Marionette to re-display the view whenever the model’s date attribute changes. For this we used the view’s modelEvents property.
  6. We instructed Marionette to clear the timer if the view is ever removed from the DOM.

React implementation

To implement the requirements in React:

  1. We created a component to represent the clock.
  2. We stored the date in the component’s local state.
  3. We created the timer for updating the date and set it to update the component’s local state every second. We did this in the component’s componentDidMount lifecycle method. This method is called after the component has been rendered to the DOM.
  4. We created a JSX expression for displaying the date, outputting it right there in the component’s render method.
  5. We instructed React to clear the timer if the component is ever removed from the DOM. We did this in the component’s componentWillUnmount lifecycle method.

Analysis

Marionette and React are a little more in line with each other here. There are a similar number of steps involved in implementing this functionality in either framework. The only major difference appears to be related to re-displaying the date. We have to instruct Marionette explicitly to listen for changes to the model so that it knows when to re-display the view. React, on the other hand, propagates changes in state to the component via props.

CHARACTER COUNT

  • Marionette: 976
  • React: 552

Conclusion

Clearly this comparison only touches on the basics of Marionette and React. Equally clearly our ticking clock app is simplistic to say the least. Nonetheless I think the exercise serves to illustrate some interesting differences between the two libraries, differences that for the most part come down in favor of React.

  • I like React’s declarative nature. React seems to do a bit more of the grunt work for us than Marionette. React allows us to declare components; Marionette makes us create objects.
  • I like React’s functional components. Functional code, characterized by pure functions and immutable data, in theory produces more reliable results than object-oriented code. React leans toward the former; Marionette, the latter.
  • I like React’s state management. With React, changes in state are automatically propagated to components via props. With Marionette, again there may be some manual work involved depending on your use case.

Leave a Reply

Your email address will not be published. Required fields are marked *