Morning:
Afternoon:
authWithPopupFirebase is a real-time database hosted by Google. In addition to the database, it also provides features of authentication, analytics, cloud storage, and hosting. For Noteherder, we synced the state of our app to our database on Firebase. This allowed all of our data to be persisted, even after page refreshes.
Re-base is an open source package that allows easy syncing of local state with a Firebase database. Add rebase to your project with one of the following commands:
yarn add re-base # add package using yarn
npm install re-base # add package using npm
Once you have re-base installed, setup is easy! First, create a new project on Firebase, then click on “Add to a web app” to see your JavaScript config object. Next, initialize a Firebase app and database in your project using the config object, and provide the database to re-base.
import Rebase from 're-base'
import firebase from 'firebase/app'
import database from 'firebase/database'
const app = firebase.initializeApp({
apiKey: "YOURAPIKEY",
authDomain: "YOURAUTHDOMAIN",
databaseURL: "YOURDATABASEURL",
projectId: "YOURPROJECTID",
storageBucket: "YOURSTORAGEBUCKET",
messagingSenderId: "YOURSENDERID"
})
const db = database(app)
const base = Rebase.createClass(db)
export default base
Finally, call base.syncState to sync your app’s local state with Firebase. The first argument to syncState is the name of the Firebase endpoint you want to sync, and the second is a configuration object.
base.syncState('myFavoriteEndpoint', {
context: this,
state: 'items'
})
Now, any time we update the state of our app, the changes will sync with Firebase in real time.
Re-base can do much more than just syncing state. There are methods for fetch, push, post, etc. To find out more about what all you can do with re-base, check out the README
For your Firebase database, you can set up rules (written in JSON) that specify the conditions under which data is allowed to be read or written. By default, a newly generated project will require that a user be authenticated to read or write any data.
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
If you do not have authentication set up yet, these values can be set to true. This allows anyone to read or write any data in the database. This can be convenient, but probably not a good idea long-term (and you will get a warning if you do that).
Additional rules can be applied per endpoint:
{
"rules": {
"emails": {
".read": true,
".write": "auth != null"
},
"texts": {
".read": true,
".write": "auth != null"
},
"users": {
"$userId": {
".read": "auth != null && auth.uid == $userId",
".write": "auth != null && auth.uid == $userId"
}
}
}
}
The above rules translate to:
uid matches the $userId of that itemFirebase isn’t just a real-time database. It can also provide authentication services via email/password, phone, or common third-party services like Github, Facebook, and Google. For Noteherder, we set up authentication via Github OAuth.
Navigate to your project in Firebase console. Click on the ‘Authenticate’ tab on the left and then on the Github logo. Copy the authorization callback URL.
Log in to Github and click on ‘Settings’. On the left hand side, click on ‘OAuth Applications’ under the ‘Developer settings’ menu. Register a new app and fill out the form.
After successfully registering the app, you’ll be taken to your new app’s settings page.
Go back to the Github authentication tab in Firebase and fill in the Client ID and Client Secret that you got from registering your app with Github.
Note: This step assumes you already have your Firebase database added to your app.
Import firebase/auth into your app’s firebase setup. Enable firebase auth and also create an instance of GithubAuthProvider.
base.js
import Rebase from 're-base'
import firebase from 'firebase/app'
import database from 'firebase/database'
import 'firebase/auth'
const app = firebase.initializeApp({
apiKey: "YOURAPIKEY",
authDomain: "YOURAUTHDOMAIN",
databaseURL: "YOURDATABASEURL",
projectId: "YOURPROJECTID",
storageBucket: "YOURSTORAGEBUCKET",
messagingSenderId: "YOURSENDERID"
})
const db = database(app)
export const auth = app.auth()
export const githubProvider = new firebase.auth.GithubAuthProvider()
export default Rebase.createClass(db)
Import auth and the githubProvider into whatever component handles the sign-in process. Call signInWithPopup on the auth object, passing the provider as a parameter. This will launch a popup screen that will prompt the user to sign in using the provider you have specified.
SignIn.js
import React from 'react'
import { auth, githubProvider } from './base'
const SignIn = () => {
const authenticate = (provider) => {
auth.signInWithPopup(provider)
}
return (
<button className="SignIn" onClick={() => authenticate(githubProvider)}>
Sign In With GitHub
</button>
)
}
export default SignIn
Once the user has authenticated via the popup, the state of our authorization has changed (we now have an authenticated user). Other events that can cause auth state changes are signing out, timeouts, and page refreshes. We should probably set up something to listen for these events. In the componentWillMount lifecycle hook that runs when the Component is first getting loaded, we can call the onAuthStateChanged method provided on the global auth object to set up such a listener.
App.js
// ...
componentWillMount() {
auth.onAuthStateChanged(
(user) => {
if (user) {
// finish signing in
this.authHandler(user)
} else {
// finished signing out
this.setState({ uid: null })
}
}
)
}
// ...
What the authHandler callback does is up to you, but for Noteherder, we had it do pretty typical things - save the user ID to state, and initialize syncing our local state for ‘notes’ with the data stored on Firebase.
App.js
// ...
authHandler = (user) => {
this.setState(
{ uid: user.uid },
this.syncNotes
)
}
// ...
Signing out when using Firebase for authentication is also simple - just call auth.signOut()! Once the promise returned by signOut has resolved, you can handle any additional cleanup. In Noteherder, we stop syncing with Firebase and set state.notes back to an empty object.
App.js
// ...
signOut = () => {
auth
.signOut()
.then(
() => {
// stop syncing with Firebase
base.removeBinding(this.ref)
this.setState({ notes: {} })
}
)
}
// ...
Deploying an app like Noteherder is fairly simple at this stage, as it runs entirely on the client side (the browser). create-react-app makes it even easier.
create-react-app includes detailed instructions for deploying with GitHub Pages in the README.
Start by running the included build script.
yarn build # build with yarn
npm run build # build with npm
This builds the browser-ready version of our app in a build directory. (There are several aspects of our src directory that make it less than ideal for production use. For example, recall that our app is written using JSX, which browsers don’t understand.)
It also prints out these instructions:
The project was built assuming it is hosted at the server root. To override this, specify the homepage in your package.json. For example, add this to build it for GitHub Pages: "homepage" : "http://myname.github.io/myapp",
To host the app on GitHub Pages (learn more about GitHub Pages), add the “homepage” line to package.json, just like it says, substituting your GitHub user name and repository name. In my case:
"name": "noteherder",
"version": "0.1.0",
"homepage": "http://xtbc17s2.github.io/noteherder",
Now run build again.
yarn build # build with yarn
npm run build # build with npm
This time, the output will include some more specific instructions.
The build folder is ready to be deployed. To publish it at http://xtbc17s2.github.io/noteherder, run: yarn add --dev gh-pages Add the following script in your package.json. // ... "scripts": { // ... "predeploy": "npm run build", "deploy": "gh-pages -d build" } Then run: yarn run deploy
Cool! Let’s add the gh-pages package.
yarn add --dev gh-pages # with yarn, or...
npm install --save-dev gh-pages # with npm
Now let’s add those two scripts to package.json.
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
}
Now whenever you’re ready to deploy, you can just run yarn deploy!
yarn deploy # deploy with yarn
npm run deploy # deploy with npm
And your app will be available at the homepage listed in your package.json—in my case, http://xtbc17s2.github.io/noteherder.
Noteherder morning | afternoon
componentWillReceiveProps works.npm run deploy or yarn deploy to update the version on GitHub Pages.NoteForm, and assign the same functionality to the “+” button in the sidebar.