This post originally appeared on Engine Yard.
There are so many JS frameworks! It can get tiring to keep up to date with them all.
Joking aside, when it comes to choosing frameworks for a project, emerging frameworks just haven’t been battle-tested enough for me to recommend to clients in most cases.
But like much of the community, I feel pretty confident in the future of React. It’s well documented, makes reasoning about data easy, and it’s performant.
Since React only provides the view layer of a client-side MVC application, I still have to find a way to wrap the rest of the application. When it comes to choosing a library that I’m confident in, I still reach for BackboneJS. A company that bets on Backbone won’t have trouble finding people who can work on their code base. It’s been around for a long time, is unopionated enough to be adaptable to many different situations. And as an added bonus, it plays well with React.
In this post, we’ll explore the relationship between Backbone and React, by looking at one way to structure a project that uses them together.
A Note About Setting Up Dependencies
I won’t go over setting up all of the package dependencies for the project here, since I’ve covered this process in a previous post. For the purposes of this article, you can assume that we’re using Browserify.
One package that is worth noting, though, is ReactBackbone. It will allow us to trigger an automatic update of our React components whenever Backbone model or collection data changes. You can get it with
npm install --save react.backbone.
We’ll also be making use of backbone-route-control to make it easier to split our URL routes into logically encapsulated controllers. See “caching the controller call” in this article for more information about how to set this package up.
There are many ways to structure the directories for a client-side JS application, and every project lends itself to a slightly different setup. Today we’ll be creating our directory structure in a fairly typical fashion for a Backbone project. But we’ll also be introducing the concept of screens to our application, so we’ll also be extending it slightly.
Here’s what we’ll need:
1 2 3 4 5 6 7 8 9 10 11 12
Much of this is standard Backbone boilerplate. The
vendor/ directories are self-explanatory. We’ll store reusable UI components, such as pagination, pills, and toggles, in
The heart of our app will live in the
screens/ directory. Here, we’ll write React components that will handle the display logic, taking the place of traditional Backbone views and templates. However, we’ll still include thin Backbone views to render these components.
We’ll talk more about screens in a moment. For now, let’s take a look at the how a request will flow through the application, starting from the macro level.
We’ll begin by writing a root-level
index.js file, which will be the source of the
require tree that Browserify will use.
1 2 3 4
What is this
Application, you may ask? Simply put, it’s the function we’ll use to bootstrap the entire project. Its purpose is to get all of the dependencies set up, instantiate the controllers and router, kick off Backbone history, and render the main view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
Once the application has been booted up, we’ll want to be able to accept requests. When one comes in, our app will need to be able to take a look at the URL path in the navigation bar and decide what to do. This is where the router comes in. It’s a pretty standard part of any Backbone project, so it probably won’t look too out of the ordinary, especially if you’ve used
1 2 3 4 5 6 7 8 9 10 11 12
When one of these routes is hit, the router will take a look at the controllers we passed into it during app initialization, find the controller with the name to the left of the
# and try to call the method name to the right of the
# in the string defined for that route.
For the purposes of this post, we’ll just have a
UsersController with two actions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
This controller loads the
User model and collection, and uses them to display the user index and show screens. It instantiates a Backbone collection or model, depending on the route, fetches its data from the server, loads it into the screen (which we’ll get to momentarily), then shows that screen in the app’s
At this point, we’ve accepted a request, routed it through a controller action, decided what kind of collection or model we are dealing with, and fetched the data from the server. We’re ready to render a Backbone view. In this case, it will do little more than pass the data on to the React component.
The Base View
Since there’s going to be a lot of repeated boilerplate in our Backbone views, it makes sense to abstract it out into a
BaseView, which child views will extend from.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This base view sets any options passed in as properties on itself, and defines a
render() method that renders whatever React component is defined in the
The Main View
In order to switch between screens without doing a page re-render, we’ll wrap all of our screens in an outer screen called the
mainView. This view acts as a sort of “picture frame” for the other screens in the app, displaying, hiding, and cleaning them up.
As with all of our screens, it will consist of two parts: a Backbone view, defined in
screens/main/index.js, and a React component, defined in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Since we passed
#app as the element for this view to attach to back in
app.js, it will render itself there. Thinking through what
render actually means, we know that it will call the code defined in the
BaseView, which means it will render the whatever’s returned by the
component() function. In this case, it’s the React
MainComponent. We’ll take a look at that in a moment.
The other special thing this view does is to render any subviews passed to
pageRender in the
#main-container element found within
#app. As I said, it’s basically just a frame for whatever else is going to happen.
Now let’s take a look at that
MainComponent. It’s a very simple React component that does nothing more than render the “container” into the DOM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
That’s it, the whole
MainView. Since it’s so simple, it makes a good introduction to how we can render components in this project.
Now let’s take a look at something a little more advanced.
User Show View
We’ll start by taking a look at how we might write a React component for a user show page.
First, we’ll define the
UserShowView we referenced back in the
UsersController. It should live at
1 2 3 4 5 6 7 8 9 10 11 12
That’s it. Mostly just boilerplate. In fact, pretty much all of our Backbone views will look like this. A simple extension of
BaseView that defines a
component() method. That method instantiates a React component and returns it to the
render() method in the
BaseView, which in turn is called by the
Now, let’s dig into the meat of user show screen: the
UserScreen component. It will live at
We’ll imagine that we can “like” users. We want to be able to increment a user’s
likes attribute by clicking a button. Here’s how we’d write this component to handle that behavior.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
You may have noticed that curious
mixins property. What is that?
react.backbone gives us some niceties here, since we’re calling
React.createBackboneClass instead of
React.createClass. Whenever the
user prop that was passed into this component fires a
change event, the component’s
render() method will be called. For more information, take a look at the package on GitHub.
When we click that like button, we’re incrementing the
likesCount attribute on the user, and saving it to the server with our
save() call. When the result of that
sync comes back, our view will automatically re-render, and the likes count indication will update! Pretty sweet!
Users Index Screen
Before we conclude this post, lets take a look at one more case: the index screen. Here, we’ll see how using React can make it easier to render repetitive subcomponents.
The view for this screen will live at
/screens/users/index/index.js, and look similar to the
1 2 3 4 5 6 7 8 9 10 11 12
UsersIndexScreen component will also be fairly similar to the
UserShowScreen one, but with one key difference: since we’re going to be rendering the same DOM elements repeatedly, we can leverage subcomponents.
Here’s the main component, which lives at
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
We’re just looping through the users that were passed into the component, and wrapping each one in a
UserBlock React component. This component can be defined in a file that lives right alongside
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Voila! An index view at
/users that shows all of our users’ beautiful faces and links to their show pages. It was pretty painless, thanks to React!
We’ve now traced the entire series of events that happens when someone loads up our application and requests a route. After going through the router and controller, the fetched data is injected through a Backbone view into a React component, which is then rendered by the app’s
We only barely scratched the surface of what React is capable of here. If you haven’t checked out the React component API docs, I highly suggest doing so. Once I began to fully harness the power it gave me, I found my projects’ view layers much cleaner. Plus, I get all of the React performance benefits for free!
I hope that this post has helped make it more obvious how to get started with integrating React into a Backbone app. To me, it always seemed like a good idea, but I didn’t know where to begin. Once I got a sense of the pattern, though, it became pretty easy to do.
P.S. Do you have a different pattern for using React in your Backbone app? Want to talk about using React in Ember or Angular? Leave us a note in the comments!