Transitioning Your Marionette App to React
Backbone.js and Marionette are great frameworks that people use even today to write front end applications. That being said, there are reasons that you may want to explore using new frameworks, like React, but you’re not sure how to do it. It’s a pretty reckless idea to decide to rewrite your entire front end in a new framework, so don’t do that. Instead, try to experiment by introducing a new technology to your stack and see how it works. Using webpack and asynchronous imports, you can even introduce new technologies to your bundle without increasing the initial bundle size.
In this article I’m going to explain how I introduced React into my existing Marionette project!
My first experiment with introducing React to the application was a bit like this:
What’s going on in the above code example? Well, I’m still using a Marionette View as I did anywhere else in the Marionette application. What’s different is that I’m returning JSX from the template instead of a raw html string. This doesn’t actually render correctly, so I have to tell React to render itself into the root element of the view once it finishes rendering via the Marionette View lifecycle.
After that, React takes over and begins its lifecycle events. This is where things got hairy. React and Marionette both managing a component’s lifecycle events was bound to get ridiculous once I started introducing any normal amount of complexity to the component, like clicking buttons and inputing values into text inputs. Which library should re-render? Marionette? React? Who knows?
So I went back to the drawing board. With the help of my colleague, I came up with this:
In this example, I’m doing a few things. I’m starting out with a Marionette view, to be used like any other Marionette View would be used (
new ReactComponent() ). The difference between this component and the first one is that instead of trying to make Marionette coexist with React, I’m just handing off responsibility of rendering from Marionette to React. The one constructor option you should pass to this View on instantiation is the actual React component you are going to render, and this takes care of the rest. Example:
Now we’ve drawn a line in the sand between where our Marionette app ends and where React picks up, inside of
ReactComponent itself, we manage the lifecycle of a React component so it graceful destroys itself when the parent re-renders and thus destroys the view, via
Great! So now, what if we have a complex Marionette View that we don’t want to necessarily refactor it on our path to React world? That’s fine, we have a solution for that. Meet the other half of this,
This view can be rendered just like any React component, but ends up being managed by whatever Marionette View you throw at it. Example:
The above example will create the
TextInput view with the other props passed to
ReactToMarionette . In this case it’s just
I hope you found this helpful! With this strategy, you can start writing code for another library/framework and deprecate your old stuff gracefully rather than immediately have to rewrite everything on day 1. I’m sure this strategy could be employed with other libraries/frameworks to accomplish the same goal, such as going from Marionette to Vue or angular 1.x to React.