Tip: Getting Backbone and React to talk to each other

Here’s a quick tip for getting Backbone and React interacting nicely.
Forgive the Coffeescript examples, but it’s what we tend to use at Revelry.
I’m going to show you how to create a mixin that rewrites your props into the
Backbone objects you really want, then binds events to make your UI update
automatically when their data changes.

There are certainly some parts of this you may want to throw out, but let’s just
start with defining a mixin:

BackboneProps =

  # Component should contain a map of prop names to Backbone classes, like:
  #
  # backboneMap:
  #   users: User.Collection

  # Set up our Backbone instance objects.
  componentWillMount: ->
    @__bb = []
    for name of @backboneMap
      data = @props[name]
      if data?
        # Rewrite the prop as the correct Backbone model or collection.
        klass = @backboneMap[name]
        @props[name] = new klass(data)
        # Save a reference so we wire up events.
        @__bb.push @props[name]

  # Whenever there may be a change in the Backbone data, trigger a reconcile.
  componentDidMount: ->
    _.each @__bb, (model) =>
      model.on "add change remove", @forceUpdate.bind(this, null), this

  # Clean up any dangling references when the component is destroyed.
  componentWillUnmount: ->
    _.each @__bb, (model) =>
      model.off null, null, this

Fairly straightforward if you read the comments.
For many developers, it might make more sense to skip the data-to-class-name
mappings and just pass a Backbone object straight in.
In which case all you would need to know is which props are Backbone models
or collections so that you can bind and unbind the events.

But at Revelry, we tend to:

  • Give each page of the application a single component at the top of the hierarchy
  • Render it server-side on initial page load by passing in JSON from a custom Rails renderer
  • Bind Backbone events only at the top of the component hierarchy

This code works quite well under those constraints.
If you have a vastly different architecture, consider hacking this up to fit
better with your needs. (Read: We know it works in our stack, but we can’t speak for yours.)

Anyway, let’s get to it. You can now create awesome components that instantly
update when Backbone data changes, like this:

React.createClass "UsersList",
  mixins: [BackboneProps]

  backboneMap:
    users: UserCollection

  render: ->
    <div>
      <ul>
        {@users.map (user) => <li>{user.get "name"}</li>}
      </ul>
      <input ref="nameInput" type="text" />
      <button onClick={@onClickAdd}>Add user</button>
    </div>

  onClickAdd: (e) ->
    e.preventDefault()
    @props.users.add
      name: @refs.nameInput.getDOMNode().value

We build digital products to help companies scale, automate workflows, and deliver on innovation faster than their competitors.

We’re always looking for folks who will bring something to the team.

Keep in touch by subscribing to Coding Creativity,
a weekly digest of the product, design, and development news that fuels our industry.

More Posts by Joel Wietelmann: