This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Building a React.js App: Using ReactFire to Add Data Persistence

14:09 React lesson by

In this video, we’ll tie in ReactFire from Firebase in order to implement persistence into our application for our Notes component as well as walk through how to properly display a list of data.

Click here for JSON data to seed your database.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

In this video, we’ll tie in ReactFire from Firebase in order to implement persistence into our application for our Notes component as well as walk through how to properly display a list of data.

Avatar
Chris

Would you mind including an export of your firebase instance?

Avatar
Kent C.

If I'm not mistaken, ReactFire will unbind the refs that you bind automatgically (here).

However, because you create an additional reference to a Firebase that is not explicitly bound, do you not have to clean up that one? I'm talking about the this.ref = new Firebase('...'); I'm asking honestly. I don't know whether you have to clean that up yourself or not.

Avatar
Paul

+1 I really need the data to go any further

In reply to Chris
Avatar
Michael

+1 on the data. Would it be possible to add this to the Github repo @Tyler?

Avatar
Benjamin

I just created my own data at Firebase. I only made one user. Also, I've never used Firebase before. It took me about 30 min (including the Firebase tutorial) to figure it out.

Avatar
Joel

Here's some JSON to seed your database.

Avatar
Marcelo

I see some people I little frustrated because of the Firebase part: just create an account in case you don't have one. In Firebase go to Data in the upper right corner. Go to this link http://cloud.egghead.io/code/0s1a2x2X3P2c and copy that JSON or download the file, you once do it, create a JSON file with that info, then hit Import Data, and select the JSON file you just create. That's it.

Avatar
miguel

you have any idea why the data i am getting is returning both the property and value, instead of just the value like in the video

In reply to Marcelo
Avatar
miguel

componentDidMount: function(){
this.ref = new Firebase('https://githubnote-taker.firebaseio.com');
var childRef = this.ref.child(this.getParams().username);
this.bindAsArray(childRef, 'notes');
}
This is what i have, but when i run this, my notes shows both the property and the value like this
Notes: What a guy-JugSizVlM-1ijz6OPxZNew note-JugSlbdwr9jTIZZjurt
What am i doing wrong? how do i get just the value like in the video?

Avatar
miguel

There was an update to ReactFire on the 15th and i think that had something to deal with it, still not sure how to fix it

In reply to miguel
Avatar
Joel

Talked to Tyler and he said the new 0.5.0 release of ReactFire is causing issues and that for the sake of the lesson you will want to explicityl npm install reactfire@0.4.0 --save to use v0.4.0 for now. We will update the video as soon as possible, but the "old" version works fine.

In reply to miguel
Avatar
Jesper

Hi,

I get this weird problem whenever I require ReactFireMixin:

Uncaught TypeError: Cannot set property 'ReactFireMixin' of undefined

Avatar
Tyler

Did you npm install reactfire?

In reply to Jesper
Avatar
Jesper

npm install reactfire@0.4.0 --save

console inspect shows me reactfire package file line 16 as an error. So its there and all, however itself triggers an error.

this is how i require:
var ReactFireMixin = require('reactfire');
and it instantly gives an error.

In reply to Tyler
Avatar
Tyler

Hmmm. Mind throwing it up on Github and I'll take a look?

In reply to Jesper
Avatar
Tyler

I just requested access to the doc.

In reply to Jesper
Avatar
Aarron

Getting the same error as Jesper...
Uncaught TypeError: Cannot set property 'ReactFireMixin' of undefined

Any ideas on this issue?

Avatar
Tyler

You're correct on the ReactFire automagical unbounding comment. (but explicit is better, right? :) ).

About this.ref, I've never worried (or seen anyone worry) about cleaning up any new instances of Firebase. I could be mistaken (really hope I'm not) but I don't think you have to clean up instances of Firebase like you would, say setting an actual listener.

In reply to Kent C.
Avatar
Nate Peterson

Rather than downgrading the version of reactfire, you can also update your code in NotesList.js. In the part where you are using the map function to generate an array of list items, just update the contents of the list item from {note} to: {note['.value']}

Looking at the Firebase docs, I'm still not positive this is the "correct" way to do this, but it works for now.

In reply to miguel
Avatar
odfw

I was still experiencing this even with the 0.4.0 of reactfire, seems there were some updates on firebase as well. Along with the reactfire@0.4.0 I also had to use npm install firebase@2.2.7 --save before the tut stopped showing the value:key in the notes.

In reply to Joel
Avatar
Andrew

componentDidMount: function(){
this.ref = new Firebase('https://githubnote-taker.firebaseio.com');
var childRef = this.ref.child(this.getParams().username);
this.bindAsArray(childRef, 'notes');
}
This is what i have, but when i run this, my notes shows both the property and the value like this
Notes: What a guy-JugSizVlM-1ijz6OPxZNew note-JugSlbdwr9jTIZZjurt
What am i doing wrong? how do i get just the value like in the video?

I was able to get the desired results by modifying line 7 of NotesList.js to reference only the value of the database key:value pair.

{note['.value']} instead of {note}

EDIT: Looks like Nate beat me to it by a bit. That's what I get for not reading page 2.

In reply to miguel
Avatar
egghead.io

The lesson video has been updated!

Avatar
kennly

Tyler,
I am having the same issue in the updated tutorial.
"Cannot set property 'ReactFireMixin' of undefined"
is there anyway to solve it?

In reply to Tyler
Avatar
Tyler

Hi Kennly,

Make sure all your code is matching what's in the Repo (https://github.com/tylermcginnis/github-notetaker-egghead/blob/05-reactfire/app/components/Profile.js) quite a few people have gone through the updated videos (including myself again) and we haven't had any issues. If issues persist, post your code on github and tweet me the link and I'll check it out.

In reply to kennly
Avatar
compile

Installed reactfire and got this warning:

npm WARN In reactfire@0.5.1 replacing bundled version of react with react@0.13.3

From Cli,

$ npm list react

├── react@0.14.3
└─┬ reactfire@0.5.1
└── react@0.13.3

Does it mean reactfire uses react@0.13.3 instead of the installed version, 0.14.3?

Avatar
Tyler

Yeah you're exactly right. I'm actually not sure why React-Fire has React as a dependency. I'm investigating further right now.

In reply to compile
Avatar
Luis

I keep getting these warnings that look like these:
WARNING in ./~/react/lib/ReactBrowserEventEmitter.js
There is another module with an equal name when case is ignored.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Rename module if multiple modules are expected or use equal casing if one module is expected.

Avatar
Tyler

Check that the spelling on your imports is correct. If everything looks good, compare what you have with what's in the Repo on github.

In reply to Luis
Avatar

Hi Tyler,

For what it is worth, I'm having the same problem as Kennly. I can't see where the code varies. Seems to be a webpack issue in my opinion.

if (true) {
        // AMD
        !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
          return root.ReactFireMixin = factory();
        }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
      } else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
        // CommonJS
        module.exports = factory();
      } else {
        // Global variables
        root.ReactFireMixin = factory();
      }

The error occurs on the line
return
root.ReactFireMixin = factory();
where
apparently root
is
undefined. Not sure what to make of it.

In reply to Tyler
Avatar
Mark Harrell

6:14: "Whoa"? XD

Avatar
Ashwin

How do you get your npm install to look so good with the real-time feedback?

Avatar
Tyler

Hi Ashwin. Not 100% sure to be honest. Which version of npm are you running? I'm running npm3.

In reply to Ashwin
Avatar
mLuby

In case anyone else runs into this, I was getting Uncaught Error: ReactFire: this.state.notes is not bound to a Firebase reference. The this.unbind('notes') was the culprit, so I removed it. Based on previous comments it sounds like the unbinding happens automagically anyway.

Avatar
Springload

I'm having trouble with my code - I don't seem to be getting the objects with the key and values.
I am using gulp instead of webpack, but was wondering if someone could have a look at my code and see where I am going wrong? https://github.com/claireynz/git-search

Avatar
Tyler

You're using an old version of React Fire. You're using 0.4.0 when you need to use >0.5.0

In reply to Springload
Avatar
Saravanan

Hi Tyler, I just subscribed today to egghead.io. Thanks for the wonderful videos. I am currently working on a migration project to migrate GWT to React Js. The legacy application has a bunch of servlets that interacts with GWT code. What would be a good approach to have React JS code interact with servlets? Can you point me to any resource that you may have in egghead?

Avatar
Philip Hancock

Hi Tyler,

I am having the same problem with the Cannot set property 'ReactFireMixin' of undefined Error and can't see any code errors. I have just started Egghead.io today specifically for this course. Can you see any problems in my Code?

https://github.com/pdhancock/egghead-react-gh-notetaker

I am stuck at Video 5..

Thanks,

Philip

Hi Tyler,

For what it is worth, I'm having the same problem as Kennly. I can't see where the code varies. Seems to be a webpack issue in my opinion.

if (true) {
      // AMD
      !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
        return root.ReactFireMixin = factory();
      }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
    } else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
      // CommonJS
      module.exports = factory();
    } else {
      // Global variables
      root.ReactFireMixin = factory();
    }

The error occurs on the line
return
root.ReactFireMixin = factory();
where
apparently root
is
undefined. Not sure what to make of it.

Avatar
Tyler

Hmm your code does appear to be the same but I opened my version and then moved that bundle over to your project and it worked - so there's gotta be a difference somewhere. I'll keep looking and see if I can find anything.

In reply to Philip Hancock
Avatar
Rebecca

Hi,

I'm pretty focused on learning React, and I'm struggling to find what I need in Firebase. I wish you'd gone a little more slowly in teaching the basics of Firebase and introduced the concepts in a whole additional video - this was glossed over very quickly.

Avatar
Tyler

Hi Rebecca,

That's a fair request. Have you checked out the Firebase docs? They've actually put a lot of thought and emphasis on them so they should have everything you're looking for. Let me know if I can help.

Tyler

In reply to Rebecca
Avatar

I'll second Rebecca's request. I was making good progress in the tutorial until the Firebase part.

Do I need to change the firebase url in Profile.js to my specific account somehow? Or should the line work as shown in the tutorial and github file?:
this.ref = new Firebase('https://github-note-taker.firebaseio.com/');

I'm working from a Cloud9 ide -- might that introduce some 3rd party authentication requirement when trying to reach firebase?

In reply to Tyler
Avatar
Tyler

The URL should still work and Cloud9 shouldn't be causing problems. Check your code against the master repo for any differences if you're having issues. https://github.com/tylermcginnis/github-notetaker-egghead. If you're still stuck let me know and I can help.

In reply to
Avatar
Tyler

Hi Saravanan, I have 0 experience with GWT so I can't offer many suggestions. Sorry!

In reply to Saravanan
Avatar

Got it working -- though more by accident (hindered by an obvious lack of logical thinking on my part).

a) I had to first (duh) type a user name that exists in your firebase instance (i.e., 'tyler') -- suddenly I had the notes. I had a random user name in the url from playing around in the prior lessons -- so of course no notes were found for this random username.

b) my chrome dev tools is not showing the listening activity (though has behaved generally per the tutorial) -- this threw me off as there's no evidence of the listening -- still not sure why this is, but once I had a good username that pulled notes, this is less of an issue.

c) to do the interactivity proof you show in the tutorial, I had to substitute your firebasio.com url with my own account (and using the json data provided at the request of other users). This seems obvious now, but from the tutorial and your reply above I was working under the impression that I wouldn't need to have an account or change the url to do exactly as the tutorial shows. So much is explained so well (and so specifically) that the lack of a qualifier in this case tripped me up. ("of course you'll need to type a username that's in the database, like 'tyler' or..."; "if you want to test the interactivity you'll need to create your own firebase account, upload the json data and change the url to your account...").

So, small complaints aside, I'm a customer because your tutorials are well paced, very specific, and comprehensive -- even if on occasion I need the obvious stated just a little more obviously.

In reply to Tyler
Avatar
Tyler

Thanks for the in depth and very rational critique. Feedback is noted.

In reply to
Avatar
Shankar Dhanasekaran

i am getting following error in console. How could i fix it?

Uncaught Error: Invariant Violation: Objects are not valid as a React child (found: object with keys {.value, .key}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of Notes.

i am using the same code at https://github.com/tylermcginnis/github-notetaker-egghead/blob/05-reactfire/app/components/Profile.js

Avatar
Tyler

In Notes change <p> {this.props.notes}</p> to <p> {JSON.stringify(this.props.notes, null, 2)}</p>

In reply to Shankar Dhanasekaran
Avatar
Sebastian

Any chance you can update this to work with rebase and ES6?

In reply to Tyler
Avatar
Ian Moreno

Ahhh thank you! I was making the same mistake (a) in the above comment, using a random name not included in the seed data

In reply to
Avatar
Pål Taule Brentebråten

Uncaught TypeError: Cannot set property 'ReactFireMixin' of undefined

Did anyone figure this out? I have the same problem. I have the excact same code, Uninstalled/reinstalled all the packages to the versions used in the tutorial, remade the bundle file... but still get the same error :(

In reply to Tyler
Avatar
Matthew

Thank you, I muddled through all the same issues as well, and having to type a username that existed in the database was tripping me up.

In reply to
Avatar
Bharat Soni

Nothing happens when I change the url from /Github to /Grobiou. Both are present in the JSON file. I was expecting change in notes... May be you will cover that in next video?!

Avatar
Felice

Great Solution !

In reply to
Avatar
Robert

I used your URL given in the video just to see if things worked... the short answer is things did, but there's hundreds of rows in the database now under the /tyler profile. Which locks up my browser, to the point that I thought I broke something. :-D

Importing the data into my own Firebase instance fixed this but maybe the "original" needs some cleanup.

Avatar
Wojciech Urbański

The link doesn't work anymore :(

In reply to Joel
Avatar
Justine

It's now May 2016, and Firebase still has no plan on supporting ES6, or developing a higher-order React component so that we don't have to do Mixins.
I'm learning React from the beginning right now. I have a feeling this tutorial series needs to be redone with ES6 from the beginning, and using another persistence technology that works with ES6 and modern React, and the ability to persist without an active internet connection for those of us that want to run through this tutorial offline.

Avatar
Tyler

Hi Justine,

You're making two very large assumptions here. First is that Firebase doesn't work with React without using React Fire and second is that using Classes are the standard way to create components in React.

I actually don't use React Fire because I don't feel like it's needed and it definitely doesn't work if you add a data model like Redux.

Also I, along with many Facebook developers, still use createClass over Classes in React.

Tyler

In reply to Justine
Avatar
kevin

Tyler, why do you and "many Facebook developers", use createClass over classes in react?

In reply to Tyler
Avatar
Russell

Hello all, if you're doing this post May 2016, in your Firebase you will need to change the Rules like so to get the data to display:

{
"rules": {
".read": "auth == null",
".write": "auth != null"
}
}

Avatar
Mac

For those looking to use the new Reactfire API, this got me going.
https://firebase.google.com/docs/web/setup#add_firebase_to_your_app

You also need to include your config var, where is the best place for that to go?

var config = {
  apiKey: '',
  authDomain: '',
  databaseURL: '',
  storageBucket: '',
};
Firebase.initializeApp(config);
componentWillMount: function(){
    this.ref = Firebase.database().ref('usernames');
    var childRef = this.ref.child(this.props.params.username);
    this.bindAsArray(childRef,'notes');
  },
Avatar
Ross

Thanks, Russell. I can now read data from Firebase!

In reply to Russell
Avatar
Daniel

For now I'm using like this:

// Profile.js
...
var Notes = require('./Notes/Notes');
var ReactFireMixin = require('reactfire');
var Firebase = require('firebase');

var config = {
  apiKey: "AIzaSyA9IdUO3ZMpI3-pKEuzDceKccTiGeGOp4Y",
  authDomain: "kuroski-note-taker.firebaseapp.com",
  databaseURL: "https://kuroski-note-taker.firebaseio.com",
  storageBucket: "kuroski-note-taker.appspot.com"
};
Firebase.initializeApp(config);
...
componentWillMount: function() {
  this.ref = Firebase.database().ref('/');
  var childRef = this.ref.child(this.props.params.username);
  this.bindAsArray(childRef,'notes');
},
componentWillUnmount: function() {
  this.unbind('notes');
},
render: function() {
...

And don't forget to change the rules from Realtime Database (because for now we are not authenticated)

{
  "rules": {
    ".read": true,
    ".write": true
  }
}
In reply to Mac
Avatar
Max

I have my code structured exactly as you mentioned, but I keep getting this.bindAsArray is not a function. I've also changed my rules in firebase to true but I'm still not able to get pass this error.

In reply to Daniel
Avatar
Max

I just figured it out. I was writing my code with ES6. To get your code working with ES6 classes you need to import react-mixin and include it in your code like this:

reactMixin(Profile.prototype, ReactFireMixin);

In reply to Max
Avatar
Aleksey

Thank you, that fixed the issue I had

In reply to Russell
Avatar
Shft

THANKS Russell! Can we pin this some how?

In reply to Russell
Avatar
Ben

Do people really call 'li' tags "lie" tags?

Avatar
YouYou

My Notes list on the web page are empty.
I am using the last version of ReactFire and Firebase , so I have the next code, can you please tell me if there is any mistake ?
Thanks


var Firebase = require('firebase');
var config = {
apiKey: "XXXXXXXXXXXXXXXXXXXX",
authDomain: "reactproj-XXXX.firebaseapp.com",
databaseURL: "https://reactproj-XXXX.firebaseio.com",
//storageBucket: ".appspot.com",
};
Firebase.initializeApp(config);

var Profile = React.createClass({
mixins: [ReactFireMixin],
getInitialState: function(){
return {
notes: [1,2,3],
bio: {
name: 'Tyler McGinnis'
},
repos: ['a', 'b', 'c']
}
},
componentDidMount: function(){
// V2 of reactfire
// this.ref = new Firebase('https://reactproj-abba1.firebaseio.com/');
//var childRef = this.ref.child(this.props.params.username);
// v3 of react fire:
var childRef= Firebase.database().ref(this.props.params.username);
this.bindAsArray(childRef, "Notes");
},
componentWillUnmount: function(){
this.unbind("notes");
},


Avatar
kel

Russel's comment is still golden. #google #firebase #rules

Avatar
Shawy

Hi Max, I got the same error as you mentioned. But I don't quite understand your solution, could you make it more detailed? thanks

In reply to Max
Avatar
Shawy

Just sort it out, thanks

In reply to Max
Avatar
Michael

componentDidMount: function(){
this.ref = new Firebase('https://githubnote-taker.firebaseio.com');
var childRef = this.ref.child(this.getParams().username);
this.bindAsArray(childRef, 'notes');
}
This is what i have, but when i run this, my notes shows both the property and the value like this
Notes: What a guy-JugSizVlM-1ijz6OPxZNew note-JugSlbdwr9jTIZZjurt
What am i doing wrong? how do i get just the value like in the video?
Hey!
You have to change this
"var childRef = this.ref.child(this.getParams().username);"
with
var childRef = this.ref.child(this.props.params.username)

In reply to miguel
Avatar
Michael

you need to first put this into your project.
var ReactFireMixin = require('reactfire');

In reply to Pål Taule Brentebråten
Avatar
David

Could you explain how you fixed it? I also am having trouble applying Max's solution.

In reply to Shawy
Avatar
Kylan Hurt

In case no one else has mentioned it: Google Chrome currently doesn't seem to be displaying the GUI for Firebase correctly (cannot find JSON import area, for example), but you can work-around it by using Firefox.

Avatar
Mark Berry

Thank you!!

In reply to Joel
Avatar
Alexius Hale-Dubuque

I'm getting the error: "TypeError: Firebase is not a constructor". I've tried following the Firebase docs; but, I still get the error. My 'Profile.js' code is the same as the transcript.
UPDATE: I reinstalled firebase with the following: 'npm install --save firebase@2.3.2 '. I'm no longer seeing the TypeError message; however, the Notes array is empty. I imported the JSON data object giving in the discussion. I can see the data in my firebase project; but, not in the notetaker app.

Avatar
Nathan Brenner

At 7:40 I only got logged to the console the original notes value (from getInitialState) then an empty array. I looked at the rest of the comments on this thread, tried a bunch of the suggestions, and what ended up working was changing the rules in the database.

You can set rules to the database in your repo, or you can do it directly from https://console.firebase.google.com/project/${project name}/database/rules.

By default, the values are:

{
  "rules": {
    ".read": "auth != true",
    ".write": "auth != true"
  }
}

If you change it to this, it'll work:

{
  "rules": {
    ".read": "true",
    ".write": "true"
  }
}

Aside from that, I agree that the sidetrack to Firebase has been distracting from just expecting to learn React, but I've been meaning to get into Firebase just for the sake of things like prototyping apps.

The Firebase docs were a lot of help, particularly https://codelabs.developers.google.com/codelabs/firebase-web/#0

Also, Initially when I went to the project, I was using chrome and nothing was showing up on the ui, except the navbar, but it worked on Firefox. Sounded like someone else had this issue. I updated Chrome, and restarted my macbook pro, and it worked fine. Also worked fine on my windows 10 computer.

Avatar
Gerard

i still keep getting this error:

TypeError: Firebase.initializeApp is not a function
at Object.

var ReactFireMixin = require('reactfire');
var Firebase = require('firebase');
var config = {
apiKey: "AIzaSyeJ7NFv1Q",
authDomain: "github-notapp.com",
databaseURL: "https://github-om",
storageBucket: "github-notetakot.com",
messagingSenderId: "90270"
};

Firebase.initializeApp(config);

this.ref = Firebase.database().ref('/');
var childRef = this.ref.child(this.props.params.username);
this.bindAsArray(childRef,'notes');

this tutorial really should go into the firebase part as well... wanted to learn React and not firebase..

also changed my rules in firebase to:

{
"rules": {
".read": "true",
".write": "true"
}
}

update:

got the firebase notes to pull from my own fb-db but it wouldn't iterate properly until i re-read react's docs on iterating

var notes = this.props.notes.map(function(note, index){
return {note}
this worked for me instead of {note['.value']}

also what made firebase work for me was changing not to:

{
"rules": {
".read": "true",
".write": "true"
}
}

but changing it to:
{
"rules": {
".read": "auth == null",
".write": "auth == null"
}
}

Avatar
Brent

I find this unexpected sideline into Firebase frustrating and a huge time-waster. And the links in the docs don't appear to work. (firebaseio.com is gone)

In reply to Tyler
Avatar
Sam

I'm getting the same Firebase.intializeApp is not a function error. Can we get an official update on how to use Firebase?

Avatar
Ryan

Just use local storage if you don't feel like messing around with firebase.

Now what we're going to do in this video is we're going to hook up our firebase so we can start persisting these notes, and we're going to build out the rest of this Notes component so that we get a nice little unordered list of all of our notes that are in firebase.

Notes Component

So let's go ahead and jump to our code, and what we're going to do first is we are going to use this thing called ReactFire that Firebase made that makes it so that our component state can be bound to a Firebase endpoint.

Terminal

$ npm install --save reactfire@0.5.1

Meaning whenever a Firebase endpoint changes, our state will automatically update with the data that's there. So head to your terminal and go ahead and install it's called reactfire. Then once that finishes, as a side note really quick you might be wondering why we're getting this error, that's because we've installed webpack globally so that we can use the command line tools, but we haven't installed it locally.

[unmet peer dependency](../images/react-building-a-react-js-app-using-reactfire-to-add-data-persistence-peer-dependency-error.png)

It's not really necessary, but I'm going to npm install it locally just so this error goes away.

Terminal

$ npm install --save-dev webpack

So what we'll do is go ahead and run npm install --save-dev webpack. That will make it so whenever we install new packages this error isn't getting thrown. Go ahead and head over to your Profile.js file and then require ReactFireMixin. You can do it just by requiring reactfire so what we're going to do, as the name suggests, is we are going to add ReactFire as a mixin into your component.

What we're going to do is go ahead and give your class a mixins property, and then the value is going to be an array with ReactFireMixin as the first item in that array. What this is doing is it's going to take your instance, it's going to mixin some certain functionalities so that we can use that new functionality. So this is literally taking the this keyword of your class and it's adding a few ReactFire mixin methods onto that, so that we can use those later.

Profile.js

var ReactFireMixin = require('reactfire');

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

Now what we want to do is we're going to introduce a brand new lifecycle event called componentDidMount. Here is where you're going to want to do all your Ajax requests, it's where you're going to want to set up all your Firebase listeners, the componentDidMount lifecycle event will be called right after your component mounts to the view. So it's pretty straightforward, but basically when the component mounts this callback will be called.

Profile.js

componentDidMount: function() {

},

What we're going to do here is the very thing we want to do is we're going to create a new reference to our Firebase. If you've never used Firebase before, what we're doing here is we're going to create a new instance of Firebase and we're going to pass it the URL of where our project is located.

Profile.js

componentDidMount: function() {
  this.ref = new Firebase('https://github-note-taker.firebaseio.com/');
},

So if I head over to my Firebase dashboard, you'll notice all I did was create a new project and you'll notice there's this URL.

Firebase URL

This URL is kind of the base of our project, so if I head back over to my code all I'm doing here is I'm saying, "Hey, create me a new instance of Firebase which is going to return me an object full of all these Firebase-y type properties. I'm going to save that on my instance under the refproperty. Then once I do that, I'm going to then call bindAsArray, and the reason that's this keyword now has a bindAsArray property, is because that's exactly what our ReactFireMixin did.

Profile.js

componentDidMount: function(){
    this.ref = new Firebase('https://github-note-taker.firebaseio.com/');
    this.bindAsArray();
}

It took our context, it took our this keyword and added a few properties to it and one of those is bindAsArray. bindAsArray takes two arguments the first argument is a reference to your Firebase, and the second argument is the property on your state that you want to bind the Firebase data to. So looking back at Firebase you'll notice that we have our endpoint and basically at our root location we have all these user names. If I come and click on one of these user names, notice the URL changed.

Firebase User

This gives us a little bit of insight into how we want to bind to the specific property in our state, because if we're here and we're at Tyler's profile, we want to bind to \tyler, or if we come here and the user name is \jclingwall, then we want to get all of jclingwall's information. So what we're going to do is let's go ahead and make a childRef which is this.ref.child and then we're going to pass it the username property.

Profile.js

componentDidMount: function(){
    this.ref = new Firebase('https://github-note-taker.firebaseio.com/');
    var childRef = this.ref.child(this.props.params.username);
    this.bindAsArray();
}

So .child is a Firebase thing, and it says hey dial 1 if this is our root, and it is because that's a reference we created with just the this specific URL. If we want it to then go into \jclingwall, notice how it goes \jclingwall. That's exactly what we're doing here, is we're basically just saying take our ref and then go one deeper into whatever this is, jclingwall, tylermcginnis, whatever it is.

Now what we're going to do is we're going to pass bindAsArray our childRef which is again, a reference to this specific username's endpoint in Firebase, and then we're going to pass it the property on the state that we want to bind to which is notes. So now, when this component mounts it's going to set up this binding between our local state and Firebase, and this.state.notes should be the data that's located at this specific Firebase endpoint.

Profile.js

componentDidMount: function(){
    this.ref = new Firebase('https://github-note-taker.firebaseio.com/');
    var childRef = this.ref.child(this.props.params.username);
    this.bindAsArray(childRef, 'notes');
}

What's nice as well, is whenever this Firebase endpoint changes, that's going to update our local state as well. But what we don't want to do is add all these Firebase listeners and never get rid of those. So what we're going to do is introduce a brand new lifecycle event called the componentWillUnmount.

Profile.js

componentWillUnmount: function(){
    this.unbind('notes');
},

Whenever this component unmounts, what we're going to do is we're going to call the unbind() property on ReactFire and we're going to pass it notes so that it will remove that listener so it's not always listening and not always trying to update our state even after our component has moved on. Before we forget let's go ahead and require Firebase, and also npm install Firebase so that we can do line 18 here. So I'm going to go ahead save our var Firebase = require('firebase');.

Whoa. Now then I'm going to head over here to my terminal and I'm going to npm install Firebase.

Terminal

$ npm install --save firebase@2.3.2

Now that we have Firebase, let's go ahead and make some changes to our UI. So the very first thing I'm going to do, and this is just preparatory for future lessons, is notice here we're passing in the username to UserProfile, let's go ahead and do that for our Repos component. So our Repos component has access to the username, let's also do that for our Notes component.

I'm also going to delete this.props on here, so that's not clouding anything that we see.

Profile.js

render: function(){
    return (
      <div className="row">
        <div className="col-md-4">
          <UserProfile username={this.props.params.username} bio={this.state.bio} />
        </div>
        <div className="col-md-4">
          <Repos username={this.props.params.username} repos={this.state.repos}/>
        </div>
        <div className="col-md-4">
          <Notes username={this.props.params.username} notes={this.state.notes} />
        </div>
      </div>

Then let's go ahead and go over to our Notes component and instead of just puking the notes to the screen, React is actually going to throw an error in React .14 because you can't just puke a whole array to the screen, it needs to be a string or something like that. So what we're going to do is let's go ahead and remove this line,

Notes.js

// REMOVED
<p>{this.props.notes}</p>

and now let's go ahead and just console.log notes and then this.props.notes.

Notes.js

var Notes = React.createClass({
    render: function(){
        console.log('Notes: ', this.props.notes)

So now what we should see is if we go and refresh this, let's go ahead and start webpack, all right everything's good. If we refresh this what we should see is it's logging our notes to the console. You'll notice here that it logs 1,2,3 because what we've done is in our profile view we've set the initial notes values to an array of 1, 2, and 3.

[Notes: Console Ouput](../images/react-building-a-react-js-app-using-reactfire-to-add-data-persistence-console-output.png)

Then what happens is Firebase comes and sets our listeners, and then eventually we get a bunch of our notes like this, which has a key value which is the key in our key property,

[Notes: Key: Console Output](../images/react-building-a-react-js-app-using-reactfire-to-add-data-persistence-console-output-key.png)

which is the key of the specific item in Firebase, and then a value property which is the item at that value.

[Firebase Output](../images/react-building-a-react-js-app-using-reactfire-to-add-data-persistence-firebase-output-key-value.png)

So what's cool about Firebase, this is all real time. So if I come in here and I say change this from "Hi" to "Hello" what we should see is over here, we now have brand new notes, and we see "Hello." So head back over to your code and let's finish formatting the notes component.

First, notice we're passing notes to our notes component, and we are here and so let's go ahead and change this around a little bit. Very first thing is instead of just saying notes, I'm going to have an h3 tag, and we're going to say Notes for {this.props.username}. Then below that, let's go ahead and instead of making it so this component is worried about styling everything, let's go ahead and make a brand new component. So here's our fixed example.

Notes.js

var Notes = React.createClass({
    render: function(){
        console.log('Notes: ', this.props.notes)
        return (
            <div>
                <h3> Notes for {this.props.username} </h3>
            </div>

We could have everything just be in one component, but that's kind of not the point of React, we want multiple components and we want to be able to have reusable components. So let's make a component which takes in an array of items and will loop over the array and create an unordered list for us. If we head back over to our code, let's go ahead and inside of our Notes folder, let's create a new file called NotesList.js.

Here we're going to require React and we're going to create a component called NotesList and let's go ahead and module.export that. All right, so the UI for this component is going to be pretty simple. We are going to return an unordered list has a class name of list-group which is just a bootstrap thing. Here what we want to do is we want to have a bunch of li tags that we want one li tag for each item in the array that we're going to pass this component.

NotesList.js

var NotesList = React.createClass({
    render: function(){
        var notes = this.props.notes.maps(function(note, index){

        })
        return (
            <ul className="list-group">

            </ul>
        )
    }
});

So what we're going to do is we are going to map over the notes that we're getting from the parent component. So if you've never used map before, basically all it does is it allows you to iterate through every item in an array and modify each item in an array separately, and then spit out a new array with each item modified. So say for example we had an array of 1, 2, and 3.

What we can do is we could call .map() on that array, and pass it a callback function, and then what we can do is if we return item + 1, the very first iteration or the very first time this callback is ran, item is going to be 1, or the first item in our array, and index is going to be 0, so if we return item + 1, eventually we're going to have a brand new array that looks like 2,3, and 4 getting returned from this.map function.

NotesList.js

[1,2,3].map(function(item, index){
    return item + 1
    }); //[2,3,4]

So imagine if these were all now notes, and if we were mapping over these notes what that is going to return us is a brand new array after we've modified each note. So what we're doing is if these were this.props.notes, what we can do is we can wrap each note in a list item so that we then get an array of list items with some note inside of it.

NotesList.js

this.props.notes.map(function(item, index){
    return <li> {item} </li>
    }); //[<li>Notes</li>,3,4]

So what we're going to do is for each item in the array we're going to return a new list item with a class name of list-group-item, it's going to have a key of the index, and index is just 0,1,2,3, just normal indices for arrays, and then inside of this list item, we are going to show the note at .value, and you might be asking why is .value? If you remember, what Firebase does is it wraps each item in an object that has a key property and a .value property.

NotesList.js

var NotesList = React.createClass({
    render: function(){
        var notes = this.props.notes.maps(function(note, index){
            return <li className="list-group-item" key={index}>{note['.value']}</li>

We only care currently about this .value property. Now let's go ahead and close our li tag, and now we have notes which is an array of list items, and we will just throw that here, so inside of our unordered list, we have an array of list items.

NotesList.js

<ul className="list-group">
    {notes}
</ul>

So the last thing we need to do is head back over to our Notes component and let's go ahead and require NotesList, let's delete all this stuff.

Notes.js

var React = require('react');
var NotesList = require('./NotesList');

var Notes = React.createClass({
  render: function(){
    return (
      <div>
        <h3> Notes for {this.props.username} </h3>
        <NotesList notes={this.props.notes} />
      </div>
    )
  }
})

module.exports = Notes;

Instead, we want to use NotesList and we are going to pass it notes which is coming down from our parent component. So notice that you can pass down properties as far as you want. So our notes originally started at our profile, then go to our Notes component, and then we're passing them down to our NotesList component. Let's go ahead and close this NotesList component, check that webpack is still working, it is, and in our app we should see if we hit refresh all of our items that are in Firebase.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?