- We've learned a lot about React
- Last lesson, we learned how to get data into our React components
- Today we'll learn how to integrate a real-time data source
- We'll also learn how to deploy our application
Firebase is a back end as a service (BaaS) platform. It provides:
- Hosting for your static application
- Data read/write
- User Authentication
Your React app is static, meaning that it doesn't have to run any code on the server. All a server needs to do is host your files and provide them to a client when requested. Firebase does this for you easily.
First, Let's go ahead and configure firebase
- Sign up using your google account at the firebase.io
- create an application from the firebase dashboard
- take note of the ID generated for your project
- this can be found in several places, however, the URL is the best place to look
- your project ID is found directly after
/project/ https://console.firebase.google.com/project/YOUR-PROJECT-NAME-HERE/overview
- your project ID is found directly after
- install the firebase CLI from the command line
npm install -g firebase-tools - login
firebase login - Create a project directory from the terminal
note: don't forget tocdinto the new directory - initialize the project
firebase init- select your project name from the list (using the project ID from above)
- Go back to the Firebase Console in your browser
-
Locate your Application
-
paste the code snippet into the
<body>of yourindex.htmlfile (updating it with your own API credentials)<body> <div id="message"></div> <script src="https://www.gstatic.com/firebasejs/3.4.0/firebase.js"></script> <script> var config = { apiKey: "<API_KEY>", authDomain: "<PROJECT_ID>.firebaseapp.com", databaseURL: "https://<DATABASE_NAME>.firebaseio.com", storageBucket: "<BUCKET>.appspot.com", }; </script> </body>
-
Now we are ready to start working with Firebase
A Firebase data store can be thought of simply as a JSON object in the cloud.
When you create a Firebase application, a URL is created that represents the root node of the JSON object.
Because Firebase is real-time, you don't request data in a discrete way like you do from a REST API. Instead, you listen for events on your data that signal when the data has been updated and run a callback when that happens.
For example, we can run a callback function every time our JSON object is changed
dbRef.on("value", function(snapshot) {
console.log(snapshot.val());
})Note - Events are fired immediately for existing data.
So, how does this work?
below firebase.initializeApp(config); put the following code:
// <script>
// ...
var message = document.getElementById('message');
var dbRef = firebase.database().ref().child('message');
dbRef.on('value', (snapshot) => message.innerText = snapshot.val())
// </script>
// ...There are several things going on in the above code, so let's break it down.
- We are storing the div with an ID of message in a variable
- We are creating a variable named dbRef
firebase.database()connects to the firebase real-time database associated with our app.ref()represents a specific location in your database... used for reading/writing data to that location.child()gets a Reference for the location at the specified path.
in our case, we will call this 'message' (more on this later)on()is an event listener that listens for data changes at a specific locationon()takes up to 4 argumentson(eventType, callback, cancelCallbackOrContext, context)- in this case...
- the eventType is value (listen for a change to the value)
- our callback function returns a snapshot from firebase
- using the snapshot, we will update the message div's inner text with the value of the snapshot
note: more regarding firebase.database can be found here
var ref = new Firebase("https://tts-demo.firebaseapp.com/");- Load up your app by running
open public/index.htmlfrom the command line - Open the Firebase Console (preferably side-by-side with your
index.htmlpage) - Navigate to the Database tab (located on the sidebar)
- Click on the Rules tab at the top of your Database panel and change read/write to
true
this allows you to read/write data without authentication, and should only be used in development mode - Navigate back to Data tab
- Click the green plus sign and add a message
- Watch your browser load the new message!
We can write data to firebase by using the set() method. set() takes an object as it's argument.
// ...
dbRef.set({
message: 'hello world'
});The example above replaces the data completely. Instead, you can provide an object with a partial set of keys to update.
firebase.initializeApp(config);
var message = document.getElementById('message');
var dbRef = firebase.database().ref()
dbRef.on('value',(snapshot) => message.innerText = JSON.stringify(snapshot.val()))
dbRef.set({
className: 'JS',
weeks: 10
});
dbRef.update({
className: 'JS Application Development',
students: 15
});
/* Ref is now
{
className: 'JS Applications',
weeks: 10,
students: 15
}
*/Most times, you don't want to listen to the whole JSON object, just a specific subsection. You can create a reference to a portion of your JSON object by using the reference's child() function.
Let's say your data looks like this:
{
{
class: 'JS Applications',
name: 'Shane',
computer: {
type: 'mac',
size: '15 inch'
}
}You can read and listen for changes in just the teacher object by creating a child reference like this:
var teacher = dbRef.child('teacher');
teacher.on('value',(snapshot) => message.innerText = JSON.stringify(snapshot.val()))
teacher.set({
class: 'JS Applications',
name: 'Shane',
computer: {
type: 'mac',
size: '15 inch'
}
})Child paths can be nested as deeply as you'd like.
var ShanesComputer = dbRef.child('teacher/computer');Using the instructions from Initial Firebase Config
- Create a new basic application
- Hook Up Firebase
- Create a form with:
- 1 input
- 1 button
- when the button is clicked update Firebase
- Append the new items to the screen in an unordered list
<form>
<input type="text" id="message"/>
<button id="btn"> Add </button>
</form>var message = document.getElementById('message');
var dbRef = firebase.database().ref()
var newMessage = dbRef.child('newMessage')
document.getElementById('btn').addEventListener('click', function(e){
newMessage.set({
message: message.value
})
})Let's add Firebase data to a React component. Let's start with a simple controlled component.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
inputValue: ''
}
}
_handleChange = (event) => {
this.setState({
inputValue: event.target.value
})
}
render() {
return (
<div>
<input value={this.state.inputValue} onChange={this._handleChange} />
</div>
)
}
}
export default App;Next, we'll bring in Firebase via npm npm install --save firebase. We can now import firebase just like all of our other dependencies
import React from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
//Import firebase!
import * as firebase from 'firebase';
//...Before we get started with reading/writing realtime data, we'll need to add our Firebase config.
In src/index.js add your firebase config
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import * as firebase from 'firebase';
const config = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "688056718599"
}
firebase.initializeApp(config);
ReactDOM.render(
<App}/>,
document.getElementById('root')
);Due to the fact our reference to the Database should be immutable, Add dbRef as a prop
ReactDOM.render(
<App dbRef={firebase.database().ref().child('App')}/>,
document.getElementById('root')
);We can bring in data from Firebase in the componentDidMount event.
componentDidMount(){
this.setState
this.props.dbRef.on("value", (snapshot) => {
this.setState({
inputValue: snapshot.val()
})
})
}This creates a 1-way data binding from firebase to the component. That is, every time Firebase is updated, the component's state will be updated.
If we want updates to be saved to firebase, we'll have to update our reference object.
_handleChange = (event) => {
this.setState({
newMessageInput: event.target.value
})
}Notice that this.setState() isn't necessary! This is because your callback in componentDidMount will set update the component state for you.
Note - Your data is being updated in real time. Open another browser to the same local address and watch the magic happen
Let's create a theme preview tool with React
- Create a form with controlled text inputs for color and background
- Create a 'save' button
- Create a div (500px by 500px) with an h1 that reads 'This is a preview'
- When the 'save' button is clicked, save the two values currently in the inputs to a firebase reference
- Style the div to display the text color and background color stored in Firebase at all times
- Set up the inputs to contain the names of the text and background colors saved in firebase.
One thing we haven't covered yet, is how to deal with arrays or lists with firebase. This is very similar to how we deal with other data, but with different events. We'll be using ref.push(obj) to write data and child_added, child_removed and child_changed events to read updated data
Let's build a chat app similar to what you've been building through the class challenges :)
_handleButton(event) {
this.messagesRef.push(this.refs.messageInput.value)
}class App extends Component {
constructor() {
super()
this.state = {
newMessageInput: '',
messages: [],
}
}
_handleButton = (event) => {
const messages = this.props.dbRef.child('messages')
let newMessage = this.state.newMessageInput
messages.push(newMessage)
}
_handleChange = (event) => {
this.setState({
newMessageInput: event.target.value
})
}
componentDidMount = () => {
const messages = this.props.dbRef.child('messages')
messages.on('child_added', (snapshot) => {
this._handleMessages(snapshot, snapshot.key, 'add')
})
messages.on('child_changed', (snapshot) => this._handleMessages(snapshot, snapshot.key, 'change'))
messages.on('child_removed', (snapshot) => this._handleMessages(snapshot, snapshot.key, 'remove'))
}
_handleMessages = (snap, fbKey, action) => {
let messages = this.state.messages.slice()
let msg = {}
msg[fbKey] = snap.val()
if (action === 'change'){
console.log('hi');
let selected = messages.filter((message) => {
for(var key in message) {
return key === fbKey
}
})
messages.splice(messages.indexOf(selected[0]), 1)
messages.push(msg)
} else if (action ==='remove') {
let selected = messages.filter((message) => {
for(var key in message) {
return key === fbKey
}
})
messages.splice(messages.indexOf(selected[0]), 1)
} else {
msg[fbKey] = snap.val()
messages.push(msg)
}
this.setState({
newMessageInput: '',
messages
})
}
render() {
let messages = this.state.messages.map((message, i)=>{
for(var key in message) {
var value = message[key];
}
return <li key={i}>{value}</li>
})
return (
<div>
<h1>Slick</h1>
<input value={this.state.newMessageInput} onChange={this._handleChange} />
<button onClick={this._handleButton}>Submit</button>
<ul>
{messages}
</ul>
</div>
)
}
}Write a persistant chat app with React + Firebase.
- Create a login page where the user enters their name
- Validate that the name is more than 1 character and show error otherwise
- Upon login show all previously written messages along with
- Username
- Message
- Time
- Let users enter new messages and show them in real time
- Read about firebase Authentication - https://www.firebase.com/docs/web/guide/user-auth.html
- Implement user authentication using email and password
- Style the app to your heart's content
- Deploy your app to firebase and send us a link in slack

