React and Firebase were made for each other. And with the introduction of ReactFire back in May 2014, we provided a simpler way to build apps using both technologies. Today we're announcing ReactFire 0.5.0 - the biggest update since that initial release. The update brings improved performance, a handful of bug fixes, and some extra features to simplify development.

What is ReactFire?

For those who aren't familiar, ReactFire is a React mixin. The ReactFireMixin makes it dead simple to bind data stored in Firebase to a component's state. It handles both array-like and object-like data via the bindAsArray() and bindAsObject() methods, respectively.

For example, say you have a list of messages stored in your Firebase database that looks like this:

{
  "messages": {
    "-JqpIO567aKezufthrn8": {
      "uid": "barney",
      "text": "Welcome to Bedrock City!"
    },
    "-JqpIP5tIy-gMbdTmIg7": {
      "uid": "fred",
      "text": "Yabba dabba doo!"
    }
  }
}

You can bind the message data to your component's state by calling bindToArray() in your componentWillMount() method:

var ExampleComponent = React.createClass({
  mixins: [ReactFireMixin],

  getInitialState: function() {
    return {
      messages: []
    };
  },

  componentWillMount: function() {
    var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/messages");
    this.bindAsArray(ref, "messages");
  },

  render: function() {
    // ...
  }
});

The message data is now bound to this.state.messages. Whenever messages are added, removed, updated, or moved in Firebase, those changes are reflected automatically in this.state.messages

  • no calls to this.setState() required! The bound data can be used as normal in your component's render() method:
render: function() {
  var messages = this.state.messages.map(function(message) {
    return (
<li key={ message['.key'] }>{ message.uid } says { message.text } </li>
);
  });
  return <ul>{ messages }</ul>
;
}

What's new in ReactFire 0.5.0?

The 0.5.0 release is the first major upgrade to the ReactFireMixin since its initial release. The API is still just as minimal, but a lot has changed under the hood.

The initial implementation of bindAsArray() was quite simplistic. It had poor performance and did not properly handle complex Firebase queries. The new implementation provides improved performance (especially on large data sets) and works well with all Firebase queries. Best of all, no changes to your code are required to enable these improvements.

Another major change with 0.5.0 is the addition of the .key attribute. ReactFire now adds the .key attribute to every record it creates via the bindAsArray() and bindAsObject() methods. In previous versions, it was impossible to retrieve key names for bound items. The 0.5.0 release fixes this by including the key name by adding a .key attribute to each bound item.

As an example, let's look again at the messages array from above. The resulting bound array stored in this.state.messages will be:

[
  {
    ".key": "-JqpIO567aKezufthrn8",  // New in version 0.5.0!
    "uid": "barney",
    "text": "Welcome to Bedrock City!"
  },
  {
    ".key": "-JqpIP5tIy-gMbdTmIg7",  // New in version 0.5.0!
    "uid": "fred",
    "text": "Yabba dabba doo!"
  }
]

The inclusion of .key makes it possible to easily write data back to Firebase to update, remove, or move a record in the array. All objects synced via bindAsObject() now include the .key attribute as well.

Finally, version 0.5.0 changes how primitive values (strings, numbers, booleans) are handled. As an example, say you have the following data in your Firebase database:

{
  "foo": "bar"
}

If you call bindAsObject() on the /foo/ path, previous versions bound the value as a string "bar". As of today's 0.5.0 release, the bound object now looks like this:

{
  ".key": "foo",
  ".value": "bar"
}

You have access to the key that was bound to (.key) as well as the bound value (.value). Primitive values bound via bindAsArray() behave in the same way with the primitive value being stored in .value. Non-primitive values (that is, regular JavaScript objects) have not changed and behave in the same in all versions, except for the addition of .key.

Looking Forward

There is a lot of excitement in the React community about ES6+, Relay, GraphQL, and ReactNative. Discussions about these topics are even ongoing in the ReactFire GitHub repo. We are following the new announcements and technologies closely. Since we use React in production at Firebase, we want the two technologies to work as well as possible together.

We've found that using the vanilla React and Firebase libraries together works great and somewhat replaces the need for an application architecture like Flux. Things like ReactFire simplify development further by providing a shorthand for a lot of common use cases. And community contributions like the recently released re-base library show how well Firebase can fit into new technologies like Relay. The future of a React + Firebase application tech stack is exciting and promising. The two technologies make it that much easier to build scalable apps in a fraction of the time they traditionally have taken. You can expect ReactFire to evolve alongside React over the course of the comings months.

Getting Started with ReactFire

The best place to get started with ReactFire is by heading over to the docs. We have a five minute quickstart, a guide which walks you through making an example app, and a full API reference with more examples of binding data via bindAsArray() and bindAsObject().

If you run across any bugs or have feature suggestions, please file them on GitHub. If you have questions about the API or how to build apps with ReactFire, post them on the Firebase Google Group.

We are excited to see what you create!