|
| 1 | +# Guide | ReactFire |
| 2 | + |
| 3 | + |
| 4 | +## Table of Contents |
| 5 | + |
| 6 | + * [What Is ReactJS?](#what-is-reactjs) |
| 7 | + * [Adding Firebase to Your React App](#adding-firebase-to-your-react-app) |
| 8 | + * [`ReactFireMixin`](#reactfiremixin) |
| 9 | + * [Next Steps](#next-steps) |
| 10 | + |
| 11 | + |
| 12 | +## What Is ReactJS? |
| 13 | + |
| 14 | +[ReactJS](http://facebook.github.io/react/) is a JavaScript library built by Facebook and Instagram |
| 15 | +which makes it easy to build large, complex user interfaces. The creators of React describe it as |
| 16 | +the “V[iew] in MVC.” It is not meant to be a replacement for Angular or Ember; instead, it is meant |
| 17 | +to extend their functionality by providing a high-performance way to keep a view up-to-date with |
| 18 | +JavaScript. Its special sauce is that it renders HTML using an incredibly fast virtual DOM diff |
| 19 | +algorithm, providing much better performance than competing platforms. It has a “one-way reactive |
| 20 | +data flow” which is much simpler to understand than traditional data-binding. |
| 21 | + |
| 22 | +Components - the basic building blocks of React apps - are organized in a tree hierarchy in which |
| 23 | +parent components send data down to their children through the props variable. Each component also |
| 24 | +has a `state` variable which determines the current data for its view. Whenever `state` is changed, |
| 25 | +the component’s render() method is called and React figures out the most efficient way to update the |
| 26 | +DOM. |
| 27 | + |
| 28 | +Since React’s main focus is on the user interface, React apps need something else to act as their |
| 29 | +backend. That is where Firebase comes in. It adds the “M[odel] and C[ontroller] in MVC” to React |
| 30 | +apps, making them fully functioning apps. **Using React’s straightforward binding system, it is easy |
| 31 | +to integrate Firebase in a native way with only a small amount of code.** |
| 32 | + |
| 33 | + |
| 34 | +## Adding Firebase to Your React App |
| 35 | + |
| 36 | +Let's look at the Todo app on the [React homepage](http://facebook.github.io/react/). Within the |
| 37 | +`TodoApp` component, `this.state` is used to keep track of the input text and the list of Todo |
| 38 | +items. While React ensures that the DOM stays in sync with any changes to `this.state`, the changes |
| 39 | +do not persist beyond the life of the page. If you add a few items and then refresh the page, all of |
| 40 | +the items disappear! This is because **React has no mechanism for storing data beyond the scope of |
| 41 | +the current page session**. It relies on being used with another framework to do that. |
| 42 | + |
| 43 | +**Firebase is a natural complement to React as it provides React apps with a persistent, realtime |
| 44 | +backend**. The first thing we need to do is add Firebase to your project: |
| 45 | + |
| 46 | +```js |
| 47 | +<!-- React JS --> |
| 48 | +<script src="https://fb.me/react-15.1.0.js"></script> |
| 49 | +<script src="https://fb.me/react-dom-15.1.0.js"></script> |
| 50 | + |
| 51 | +<!-- Firebase --> |
| 52 | +<script src="https://www.gstatic.com/firebasejs/3.0.3/firebase.js"></script> |
| 53 | +``` |
| 54 | + |
| 55 | +We'll need to initialize the Firebase SDK before we can use it. This should happen one time, outside |
| 56 | +of your React component. You can find more details on the [web](https://firebase.google.com/docs/web/setup) |
| 57 | +or [Node.js](https://firebase.google.com/docs/server/setup) setup guides. |
| 58 | + |
| 59 | +```js |
| 60 | +<script> |
| 61 | + var config = { |
| 62 | + apiKey: "<YOUR-API-KEY>", |
| 63 | + |
| 64 | + // Only needed if using Firebase Realtime Database (which we will be in this example) |
| 65 | + databaseURL: "https://<YOUR-DATABASE-NAME>.firebaseio.com", |
| 66 | + |
| 67 | + // Only needed if using Firebase Authentication |
| 68 | + authDomain: "<YOUR-AUTH-DOMAIN>", |
| 69 | + |
| 70 | + // Only needed if using Firebase Storage |
| 71 | + storageBucket: "<YOUR-STORAGE-BUCKET>.appspot.com" |
| 72 | + }; |
| 73 | + |
| 74 | + firebase.initializeApp(config); |
| 75 | +</script> |
| 76 | +``` |
| 77 | + |
| 78 | +Now that we have included Firebase, we can populate the list of Todo items by reading them from the |
| 79 | +database. We do this by hooking into the `componentWillMount()` method of the `TodoApp` component |
| 80 | +which is run once, immediately before the initial rendering of the component: |
| 81 | + |
| 82 | +```js |
| 83 | +componentWillMount: function() { |
| 84 | + this.firebaseRef = firebase.database.ref("items"); |
| 85 | + this.firebaseRef.on("child_added", function(dataSnapshot) { |
| 86 | + this.items.push(dataSnapshot.val()); |
| 87 | + this.setState({ |
| 88 | + items: this.items |
| 89 | + }); |
| 90 | + }.bind(this)); |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +This code first gets a reference to the `items` node at the root of the database. The call to `on()` |
| 95 | +will be run every time a node is added under the `items` node. It is important to realize that a |
| 96 | +`child_added` event will be fired for every item under the `items` node, not just new ones that are |
| 97 | +added to it. Therefore, when the page is loaded, every existing child under the `items` node will |
| 98 | +fire a `child_added` event, meaning they can easily be iterated over and added to `this.state.items`. |
| 99 | +Note that the call at the end to `bind()` just sets the scope of callback function to this. |
| 100 | + |
| 101 | +What about adding new Todo items to the database? That code is just as easy: |
| 102 | + |
| 103 | +```js |
| 104 | +handleSubmit: function(e) { |
| 105 | + e.preventDefault(); |
| 106 | + this.firebaseRef.push({ |
| 107 | + text: this.state.text |
| 108 | + }); |
| 109 | + this.setState({text: ""}); |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +Within `handleSubmit()` a new item is pushed onto the database reference which appends it to the end |
| 114 | +of the `items` node. The call to `setState()` updates `this.state.text` but does not need to update |
| 115 | +`this.state.items` as it did in the original React code. This is because the `child_added` event |
| 116 | +handler from `componentWillMount()` will be fired when a new child is pushed onto the `items` node |
| 117 | +and that code will update `this.state.items`. |
| 118 | + |
| 119 | +The last thing that needs to happen is cleaning up the database event handler: |
| 120 | + |
| 121 | +```js |
| 122 | +componentWillUnmount: function() { |
| 123 | + this.firebaseRef.off(); |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +With just the few changes above, items added to the Todo list are updated in realtime. Best of all, |
| 128 | +the items stick around if the page is refreshed! You can even open multiple tabs pointed at the same |
| 129 | +page and see them all update simultaneously, with Firebase doing all the heavy lifting. Take some |
| 130 | +time to [view the code for this example](https://github.com/firebase/ReactFire/blob/master/examples/todoApp/js/todoAppFirebaseExplicit.js) |
| 131 | +and [play around with a live demo](https://reactfiretodoapp.firebaseapp.com/). |
| 132 | + |
| 133 | + |
| 134 | +## `ReactFireMixin` |
| 135 | + |
| 136 | +Although integrating Firebase into a React app only takes a few lines of code out of the box, we |
| 137 | +wanted to make it even easier. We also want to be able to handle when array items are removed or |
| 138 | +updated from Firebase. **We built the `ReactFireMixin` to make it simple to keep `this.state` in |
| 139 | +sync with a database node.** |
| 140 | + |
| 141 | +To get started with ReactFire, include it in your project by loading the library directly from our |
| 142 | +CDN and placing it right after the React and Firebase libraries in the `<head>` tag: |
| 143 | + |
| 144 | +```js |
| 145 | +<!-- React JS --> |
| 146 | +<script src="https://fb.me/react-15.1.0.js"></script> |
| 147 | +<script src="https://fb.me/react-dom-15.1.0.js"></script> |
| 148 | + |
| 149 | +<!-- Firebase --> |
| 150 | +<script src="https://www.gstatic.com/firebasejs/3.0.3/firebase.js"></script> |
| 151 | + |
| 152 | +<!-- ReactFire --> |
| 153 | +<script src="https://cdn.firebase.com/libs/reactfire/1.0.0/reactfire.min.js"></script> |
| 154 | +``` |
| 155 | + |
| 156 | +ReactFire and its dependencies are also available from npm via `npm install reactfire` and Bower |
| 157 | +via `bower install reactfire`. |
| 158 | + |
| 159 | +After making sure to initialize the Firebase SDK again, we can then use the `ReactFireMixin` in the |
| 160 | +`TodoApp` component, add it to the component's `mixins` property: |
| 161 | + |
| 162 | +```js |
| 163 | +var TodoApp = React.createClass({ |
| 164 | + mixins: [ReactFireMixin], |
| 165 | + ... |
| 166 | +}); |
| 167 | +``` |
| 168 | + |
| 169 | +The `ReactFireMixin` extends the functionality of the `TodoApp` component, adding additional |
| 170 | +Firebase-specific methods to it. To keep `this.state.items` in sync with any changes to the `items` |
| 171 | +node, make the following change in `componentWillMount()`: |
| 172 | + |
| 173 | +```js |
| 174 | +componentWillMount: function() { |
| 175 | + var ref = firebase.database().ref("items"); |
| 176 | + this.bindAsArray(ref, "items"); |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +We simply specify that we want to bind a particular Firebase Database reference to `this.state.items` |
| 181 | +of the React component. The `ReactFireMixin` allows binding to a node as an array or as a regular |
| 182 | +JavaScript object. This creates a one-way binding from the `Firebase` reference to `this.state.items`, |
| 183 | +meaning that if the data in the database changes, so will `this.state.items`. However, if we update |
| 184 | +`this.state.items`, the database data will not change. Therefore, changes should be made directly to |
| 185 | +the database and not by calling `setState()`: |
| 186 | + |
| 187 | +```js |
| 188 | +handleSubmit: function(e) { |
| 189 | + e.preventDefault(); |
| 190 | + this.firebaseRefs.items.push({ |
| 191 | + text: this.state.text |
| 192 | + }); |
| 193 | + this.setState({ text: "" }); |
| 194 | +} |
| 195 | +``` |
| 196 | + |
| 197 | +**ReactFire allows for binding to multiple things at once.** Firebase ensures that this is all done |
| 198 | +in an efficient manner. To access the `Firebase` reference which is bound to `this.state.items`, we |
| 199 | +can reference `this.firebaseRefs["items"]` which is provided by ReactFire. Finally, calling |
| 200 | +`this.firebaseRef.off()` is no longer needed in `componentWillUnmount()` as the mixin handles this |
| 201 | +behind the scenes. |
| 202 | + |
| 203 | +You can [view the code for this example](https://github.com/firebase/ReactFire/blob/master/examples/todoApp/js/todoAppFirebaseImplicit.js) |
| 204 | +and [play around with a live demo](https://reactfiretodoapp.firebaseapp.com/). The code and demo add |
| 205 | +the ability to delete items in the array and have them automatically synced back to `this.state.items`. |
| 206 | + |
| 207 | + |
| 208 | +## Next Steps |
| 209 | + |
| 210 | +ReactJS is a wonderful framework for creating user interfaces. When picking a complementary tool to |
| 211 | +use alongside it as a backend, Firebase is the easiest and most powerful solution. In just a few |
| 212 | +lines of code you can get a React app syncing data across hundreds of clients at once. ReactFire |
| 213 | +makes this that much easier, getting rid of even more boilerplate code. |
| 214 | + |
| 215 | +Head on over to the [ReactFire API reference](reference.md) and then get started building an app |
| 216 | +with ReactFire! |
0 commit comments