Backbone & React


Seattle React Meetup

http://slides.formidablelabs.com

 @ryan_roemer | formidablelabs.com

Bridging the Old & New

Backbone.jsReact

Survey

Who's familiar with Backbone?

With React?

Goal

Craft a Backbone/React app:

  • Lean and straightforward
  • Efficient, performant in the browser
  • Capable of server-side rendering

Backbone.js

Backbone.js

Why Backbone.js?

  • Lean and mean
  • Simple, powerful abstractions
    • Models, Views, Routers
  • REST friendly

But...

  • Dependencies on jQuery, Underscore.js
  • In practice, lots of DOM churn

Formidable Labs

Formidable Labs

Backbone.js Testing

Backbone.js Testing

Let's Write Some Notes!

VanillaJS (LocalStorage)

(live) backbone-testing.com/notes/app/


github.com/ryan-roemer/backbone-testing/tree/master/notes/app

CommonJS (REST)

Modern build - CommonJS, Webpack, Backbone, jQuery, Lodash


github.com/formidablelabs/notes/tree/master/alt/commonjs

Backbone.js Abstractions

Models

A Backbone.Model contains, retrieves, and manipulates the data for your app.

A note.

Relies on $.ajax for REST transport.


Collections

A Backbone.Collection is an ordered list of models.

A list of notes.


  

Templates

A function that renders model / collection object data as HTML.


Views

A Backbone.View mediates data, event and display logic.

Display all notes, or a single note.

Where most jQuery comes into play.


Routers

A Backbone.Router routes client-side pages and mediates history.

Route between all and single note views.


Code Organization

/
  app.js          config.js
  
collections/notes.js
models/note.js
routers/router.js

templates/
  note-view.hbs   note.hbs        notes-item.hbs
views/
  note-nav.js     note-view.js    note.js
  notes-filter.js notes-item.js   notes.js
  

Bundle Size

  • Minified: 193 KB
  • Gzipped: 63 KB

React

React

Why React?

  • Virtual DOM diffing / updating
  • Server-side rendering
  • Declarative, template-like UI components

Bringing React to Notes

Let's Write More Notes!

(live) formidablelabs.github.io/notes-react-exoskeleton/app.html


github.com/FormidableLabs/notes-react-exoskeleton

React Client-side

  • Switch Backbone.js views to React components
  • Continue using Backbone.js models, collections, routers

Porting Notes

  • Let React handle all the HTML
  • No more templates / Handlebars
  • Use BB models/collections as React props
  • Update React components on Backbone.js events

Exoskeleton

Backbone.js, without the dependencies.

  • Get rid of jQuery and Underscore.js
  • Need $.ajax replacement

Code Organization

# Backbone!
app.js
collections/notes.js
models/note.js
routers/router.js

# React!
components/
  note.jsx       notes.jsx
  nav/base.jsx   nav/note.jsx         nav/notes.jsx
  page/base.jsx
  page/note.jsx  page/note/edit.jsx   page/note/view.jsx
  page/notes.jsx page/notes/item.jsx
  

Bundle Size

  • Minified: 170 KB (vs 193 KB)
  • Gzipped: 51 KB (vs 63 KB)

Notes Component

/*jshint ignore:start */
module.exports = React.createClass({
  // ...
  render: function () {
    return (
      <div>
        <NotesNav notes={this.props.notes}
                  onUpdateFilter={this.onUpdateFilter} />
        <NotesPage notes={this.props.notes}
                   filter={this.state.filter} />
      </div>
    );
  }
});

Note Component

/*jshint ignore:start */
module.exports = React.createClass({
  // ...
  render: function () {
    return (
      <div>
        <NoteNav note={this.props.note}
                 action={this.state.action}
                 handleActionChange={this.setAction} />
        <NotePage note={this.props.note}
                  action={this.state.action} />
      </div>
    );
  }
});

App HTML

var NO_SERVER_SIDE = true;
<body>
  <div class="js-content">
    <!-- No starting content -->
  </div>
  <script src="/app/js-dist/bundle.js"></script>
</body>

React Server-side

  • Import Note, Notes components server-side with CommonJS + Webpack
  • Duplicate router logic on server
  • Mirror pushState fragments with href links
  • Check out react-router

App HTML

var NO_JS = true;
<body>
  <div class="js-content">
    {{{content}}}
  </div>
  <!-- No JavaScript -->
</body>

Bootstrapped HTML

Now let's tie it all together:

  • Start with server-rendered HTML
  • Bootstrap the SPA off that
  • Client-side render from there...

Awesome!

App HTML Template

<body>
  <div class="js-content">
    {{{content}}}
  </div>
  <script class="js-initial-data"
          type="application/json">
    {{{initialData}}}
  </script>
  <script src="/app/js-dist/bundle.js"></script>
</body>

Conclusion

  •  Render and let React handle DOM diffing
  •  Server-side rendering is easy
  •  Leave jQuery behind

Parting Thoughts

  • Dataflow is... different
  • Dive in more to the ecosystem: Flux, React router, etc.

Resources