- 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.
- Sign up for firebase using your Google account at http://www.firebase.io
- Install Firebase tools using your commandline -
npm install -g firebase-tools - Log in to your firebase account from commandline
firebase login - From your React application directory, create a new Firebase app by running
firebase init(tell firebase where your dist directory is) - Deploy using
firebase deploy - See your app by running
firebase open
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. To work with it, you need to create a "Ref"
var ref = new Firebase("https://tts-demo.firebaseio.com/");var ref = new Firebase("https://tts-demo.firebaseio.com/");
ref.set({
message: 'hello world'
});If you go to https://tts-demo.firebaseio.com/, you'll see that the data's been saved.
The example above replaces the data completely. Instead, you can provide an object with a partial set of keys to update.
var ref = new Firebase("https://tts-demo.firebaseio.com/");
ref.set({
className: 'JS',
weeks: 10
});
ref.update({
className: 'JS Application Development',
students: 15
});
/* Ref is now
{
className: 'JS Applications',
weeks: 10,
students: 15
}
*/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
ref.on("value", function(snapshot) {
console.log(snapshot.val());
})Note - Events are fired immediately for existing data.
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',
teacher: {
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 ref = new Firebase("https://tts-demo.firebaseio.com/");
var teacher = ref.child('teacher');
teacher.on('value', function(v){/*... */})Child paths can be nested as deeply as you'd like.
var ref = new Firebase("https://tts-demo.firebaseio.com/");
var ShanesComputer = ref.child('teacher/computer');Let's add Firebase data to a React component. Let's start with a simple controlled component.
import React from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
class MessageApp extends React.Component {
constructor() {
super();
this.state = {
inputValue: ''
}
}
_handleChange(event) {
this.setState({
inputValue: event.target.value
})
}
render() {
return (
<div>
<input ref="messageInput" value={this.state.inputValue} onChange={this._handleChange.bind(this)} />
</div>
)
}
}
var mountPoint = document.querySelector("#app");
ReactDOM.render(<MessageApp />,mountPoint)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 Firebase from 'firebase';
//...For now, let's have our component create a firebase reference.
constructor() {
super();
this.state = {
inputValue: ''
}
this.ref = new Firebase("https://tts-demo.firebaseio.com/");
}We can bring in data from Firebase in the componentDidMount event.
componentDidMount(){
//Arrow function so callback can use component's this.setState
ref.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.ref.update({inputValue: 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
We'll start with our basic, one component, message app:
import React from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
class MessageApp extends React.Component {
constructor() {
super();
this.state = {
newMessageInput: '',
messages: []
}
}
_handleButton(event) {
var newMessage = this.refs.messageInput.value;
this.setState({
messages: this.state.messages.concat(newMessage)
})
}
_handleChange(event) {
this.setState({
newMessageInput: event.target.value
})
}
render() {
var messages = this.state.messages.map((message, i)=>{
return <li key={i}>{message}</li>
})
return (
<div>
<h1>Slick</h1>
<input ref="messageInput" value={this.state.newMessageInput} onChange={this._handleChange.bind(this)} />
<button onClick={this._handleButton.bind(this)}>Submit</button>
<ul>
{messages}
</ul>
</div>
)
}
}
var mountPoint = document.querySelector("#app");
ReactDOM.render(<MessageApp />,mountPoint)We're going to want to read and write the state.messages array from Firebase following the same steps are before:
import Firebase from 'firebase';
constructor() {
super();
this.state = {
newMessageInput: '',
messages: ['hello', 'world']
}
this.messagesRef = new Firebase("https://tts-demo.firebaseio.com/messages");
}componentDidMount(){
this.messagesRef.on("child_added", (snapshot) => {
this.setState({
messages: this.state.messages.concat(snapshot.val())
})
})
}_handleButton(event) {
this.messagesRef.push(this.refs.messageInput.value)
}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