(License: CC BY-SA 4.0)
To follow instructions in video, clone this starter repo
Example:
git clone https://github.com/soft-eng-practicum/react-auth-firebase-workshop.git
React.js is an open-source JavaScript library that is used for building user interfaces specifically for single-page applications. It’s used for handling the view layer for web and mobile apps. React also allows us to create reusable UI components. React was first created by Jordan Walke, a software engineer working for Facebook. React first deployed on Facebook’s newsfeed in 2011 and on Instagram in 2012.
ReactJS is just simpler to grasp right away. The component-based approach, well-defined lifecycle, and use of just plain JavaScript make React very simple to learn, build a professional web (and mobile applications), and support it. React uses a special syntax called JSX which allows you to mix HTML with JavaScript. This is not a requirement; Developer can still write in plain JavaScript but JSX is much easier to use.
Firebase is a Backend-as-a-Service (Baas). It provides developers with a variety of tools and services to help them develop quality apps, grow their user base, and earn profit. It is built on Google’s infrastructure. Firebase is categorized as a NoSQL database program, which stores data in JSON-like documents.
In order to create a react app, you must have Node installed on your device. If you do not have Node, download from here.
If you cloned the starter repo, open a terminal and do:
cd react-auth-firebase-workshop
npm install
npm start
(it may give a few errors and open a blank web page)
If you did NOT clone the starter repo, open a terminal and create a new React app:
npm create-react-app authentication
Once the app is created, enter the following command in your terminal.
cd authentication
npm start
npm install -g firebase-tools
Mac and Linux users would need to prepend this command with sudo
.
firebase login
firebase projects:list
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "AIzaSyAeNL3vYTqEkQ4SjY2wCZI0tVt__ZLkPIk",
authDomain: "test-55b83.firebaseapp.com",
projectId: "test-55b83",
storageBucket: "test-55b83.appspot.com",
messagingSenderId: "226842485528",
appId: "1:226842485528:web:e18496f2f84e11d188346d",
measurementId: "G-GJG1R0XZHL"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
config.js
filenpm install react-router-dom@5.2.0
You can use later version of router dom but this is what I am using for this workshop
I am also using Semantic Ui classes for the UI. See the documentation on how to install.
npm install react-hook-form@5.7.2
pages
Signup.js
Signup.js
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { signup } from '../firebase/auth';
import { Link } from 'react-router-dom';
function Signup(props) {
const { register, handleSubmit, reset } = useForm();
const [isLoading, setLoading] = useState(false);
const onSubmit = async (data) => {
let newUser;
setLoading(true);
try {
newUser = await signup(data);
reset();
} catch (error) {
console.log(error);
}
if (newUser) {
props.history.push(`/profile/${newUser.uid}`);
} else {
setLoading(false);
}
};
const formClassName = `ui form ${isLoading ? 'loading' : ''}`;
return (
<div className="login-container">
<div className="ui card login-card">
<div className="content">
<form className={formClassName} onSubmit={handleSubmit(onSubmit)}>
<div className="two fields">
<div className="field">
<label>
First Name
<input
type="text"
name="firstName"
placeholder="First Name"
ref={register}
/>
</label>
</div>
<div className="field">
<label>
Last Name
<input
type="text"
name="lastName"
placeholder="Last Name"
ref={register}
/>
</label>
</div>
</div>
<div className="field">
<label>
Email
<input
type="email"
name="email"
placeholder="Email"
ref={register}
/>
</label>
</div>
<div className="field">
<label>
Password
<input
type="password"
name="password"
placeholder="Password"
ref={register}
/>
</label>
</div>
<div className="field actions">
<button className="ui primary button login" type="submit">
Signup
</button>
or
<Link to="/login">Log In</Link>
</div>
</form>
</div>
</div>
</div>
);
}
export default Signup;
body {
background-color: #f9f9f9 !important;
font-size: 15px;
font-family: 'Titillium Web', sans-serif !important;
}
a {
text-decoration: none;
}
.ui.button,
.ui.input,
.ui.form input {
font-family: 'Titillium Web', sans-serif !important;
}
header {
height: 50px;
background: #1a2129;
position: fixed;
top: 0px;
width: 100%;
z-index: 1;
}
header h2 {
color: #fff;
margin: 0;
padding: 10px;
position: absolute;
left: 10px;
}
.app {
margin-top: 100px;
}
.login-container {
display: flex;
align-items: center;
justify-content: center;
}
.ui.card.login-card {
width: 450px;
}
.ui.form input[type='text'],
.ui.form input[type='password'],
.ui.form select {
margin-top: 10px;
}
.logout {
float: right;
position: relative;
top: 4px;
right: 15px;
}
.actions {
text-align: right;
}
.actions button {
margin-right: 5px;
}
.actions a {
margin-left: 5px;
}
import Signup from './pages/Signup';
import { Route, Switch, BrowserRouter, Redirect } from 'react-router-dom';
<BrowserRouter>
<Header></Header>
<div className="app">
<div className="ui grid container">
<Switch>
<Route exact path="/signup" component={Signup} />
</Route>
</Switch>
</div>
</div>
</BrowserRouter>
import firebase from 'firebase/app';
import 'firebase/auth';
export const signup = async ({ firstName, lastName, email, password }) => {
const resp = await firebase
.auth()
.createUserWithEmailAndPassword(email, password);
await resp.user.updateProfile({ displayName: `${firstName} ${lastName}` });
};
import React from 'react';
import { useSession } from '../firebase/UserProvider';
const Profile = () => {
const { user } = useSession();
if (!user) {
return null;
}
return (
<div>
<p>Name: {user.displayName}</p>
<p>Email: {user.email}</p>
<p>ID: {user.uid}</p>
</div>
);
}
export default Profile;
import Profile from './pages/Profile';
<Route exact path="/profile/:id" component={Profile} />
http://localhost:3000/profile/
import React from 'react';
import { logout } from './firebase/auth';
import { useHistory } from 'react-router-dom';
import { useSession } from './firebase/UserProvider';
function Header() {
const history = useHistory();
const { user } = useSession();
const logoutUser = async () => {
await logout();
history.push('/login');
};
return (
<header>
<h2>GGC</h2>
{!!user && (
<button className="ui secondary button logout" onClick={logoutUser}>
LOGOUT
</button>
)}
</header>
);
}
export default Header;
export const logout = () => {
return firebase.auth().signOut();
};
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { login } from '../firebase/auth';
import { Link } from 'react-router-dom';
function Login(props) {
const { register, handleSubmit, reset } = useForm();
const [isLoading, setLoading] = useState(false);
const routeOnLogin = async (user) => {
props.history.push(`/profile/${user.uid}`);
};
const onSubmit = async (data) => {
let user;
setLoading(true);
try {
user = await login(data);
reset();
} catch (error) {
console.log(error);
}
if (user) {
routeOnLogin(user);
} else {
setLoading(false);
}
};
const formClassName = `ui form ${isLoading ? 'loading' : ''}`;
return (
<div className="login-container">
<div className="ui card login-card">
<div className="content">
<form className={formClassName} onSubmit={handleSubmit(onSubmit)}>
<div className="field">
<label>
Email
<input
type="email"
name="email"
placeholder="Email"
ref={register}
/>
</label>
</div>
<div className="field">
<label>
Password
<input
type="password"
name="password"
placeholder="Password"
ref={register}
/>
</label>
</div>
<div className="field actions">
<button className="ui primary button login" type="submit">
Login
</button>
or
<Link to="/signup">Sign Up</Link>
</div>
<div>
<Link to="/forgotpassword">Forgot Password?</Link>
</div>
</form>
</div>
</div>
</div>
);
}
export default Login;
export const login = async ({ email, password }) => {
const resp = await firebase
.auth()
.signInWithEmailAndPassword(email, password);
return resp.user;
};
import Login from './pages/Login';
<Route exact path="/login" component={Login} />
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import { passwordReset } from '../firebase/auth';
function ForgotPassword() {
const { register, handleSubmit, reset } = useForm();
const [isLoading, setLoading] = useState(false);
const onSubmit = async (data) => {
setLoading(true);
try {
await passwordReset(data);
reset();
console.log("Please check your email address!");
} catch (error) {
console.log(error);
}
setLoading(false);
}
const formClassName = `ui form ${isLoading ? 'loading' : ''}`;
return (
<div className="login-container">
<div className="ui card login-card">
<div className="content">
<form className={formClassName} onSubmit={handleSubmit(onSubmit)}>
<div className="field">
<label>
Email
<input
type="email"
name="email"
placeholder="Email"
ref={register}
required
/>
</label>
</div>
<div className="field actions">
<button className="ui primary button login" type="submit">
Reset Password
</button>
or
<Link to="/login">Login</Link>
</div>
</form>
</div>
</div>
</div>
);
}
export default ForgotPassword;
export const passwordReset = async ({email}) => {
return await firebase.auth().sendPasswordResetEmail(email);
};
import ForgotPassword from './pages/ForgotPassword';
<Route exact path="/forgotpassword" component={ForgotPassword} />
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { useSession } from '../firebase/UserProvider';
const ProfileRedirect = ({ component: Component, ...rest }) => {
const { user } = useSession();
return (
<Route
{...rest}
render={(props) =>
!user ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: `/profile/${user.uid}`,
state: { from: props.location },
}}
/>
)
}
/>
);
};
export default ProfileRedirect;
import ProfileRedirect from './router/ProfileRedirect';
<ProfileRedirect exact path="/signup" component={Signup} />
<ProfileRedirect exact path="/login" component={Login} />
<ProfileRedirect exact path="/forgotpassword" component={ForgotPassword} />
<Route exact path="/">
<Redirect to="/login" />
</Route>
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { useSession } from '../firebase/UserProvider';
const PrivateRoute = ({ component: Component, ...rest }) => {
const { user } = useSession();
return (
<Route
{...rest}
render={(props) => {
const id = props.match.params.id;
if (!!user && (user.uid === id)) {
return <Component {...props} />;
} else {
return <Redirect to="/login" />;
}
}}
/>
);
};
export default PrivateRoute;
import PrivateRoute from './router/PrivateRoute';
<PrivateRoute exact path="/profile/:id" component={Profile} />
This bring us to the end of Authentication with React and Firebase, I hope this is going to be useful for you when creating your own react project.
The code for this tutorial can be found in my Github
Create by: Keyvan Shabani