Firebase auth with React
jagarkin
Posted on December 23, 2020
hello today I'll be talking on how I build a simple yet minimalistic to do app with react and firebase your see the app here devdo I will be highlighting the most important stuff feel free to check the code for more.
let's start by installing our dependencies
npm install react-icons --save
npm install --save styled-components
npm install react-tabs
npm i firebase
I started by creating a router with three component:
- Log in
- Sign UP
- Reset Password
- Dashboard
- Update Profiles
then I initialized the firebase SDK in in the Firebase.js folder I left the config in the code as it was only for testing
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/auth";
const app = firebase.initializeApp({
apiKey: "Xxxx Xxxx Xxxx Xxxx Xxxx",
authDomain: "Xxxx.firebaseapp.com",
projectId: "Xxxx",
storageBucket: "Xxxx Xxxx.appspot.com",
messagingSenderId: "Xxxx Xxxx ",
appId: "Xxxx Xxxx Xxxx Xxxx Xxxx"
});
export const auth = app.auth();
export const useFireStore = firebase.firestore();
export default app;
don't forgert to activate our auth methode from the firebase console in our case it's only email and password
create an AuthProvider so that we have firebase auth on top
import React, { useContext, useEffect, useState } from "react";
import { auth } from "./Firebase";
const AuthContext = React.createContext();
export function useAuth() {
return useContext(AuthContext);
}
export default function AuthProvider({ children }) {
const [loading, setLoading] = useState(true);
const [currentUser, setCurrentUser] = useState();
const signup = (email, password) => {
return auth.createUserWithEmailAndPassword(email, password);
};
const login = (email, password) => {
return auth.signInWithEmailAndPassword(email, password);
};
const logout = () => {
return auth.signOut();
};
const resetPassword = email => {
return auth.sendPasswordResetEmail(email);
};
const updateEmail = email => {
return auth.updateEmail(email);
};
const updatePassword = password => {
return currentUser.updatePassword(password);
};
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const value = {
currentUser,
signup,
login,
logout,
resetPassword,
updateEmail,
updatePassword
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
then we need a protected route to prevent non logged users to access certain component
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useAuth } from "../utils/AuthContext";
const PrivateRoute = ({ component: Component, ...rest }) => {
const { currentUser } = useAuth();
return (
<>
<Route
{...rest}
render={props => {
return currentUser ? (
<Component {...props} />
) : (
<Redirect to='/login' />
);
}}></Route>
</>
);
};
export default PrivateRoute;
then in our App.js we create our routing as you'll notice that we wrapped everything in an app provider
import Login from "./components/services/Login";
import Signup from "./components/services/Signup";
import Dashboard from "./components/pages/Dashboard";
import PrivateRoute from "./components/utils/PrivateRoute";
import AuthProvider from "./components/utils/AuthContext";
import UpdateProfile from "./components/services/UpdateProfile";
import ForgotPassword from "./components/services/ForgotPassword";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
function App() {
return (
<>
<AuthProvider>
<Router>
<Switch>
<PrivateRoute exact path='/' component={Dashboard} />
<PrivateRoute path='/update-profile' component={UpdateProfile} />
<Route path='/signup' component={Signup} />
<Route path='/login' component={Login} />
<Route path='/forgot-password' component={ForgotPassword} />
</Switch>
</Router>
</AuthProvider>
</>
);
}
export default App;
now after creating our auth service let's hover on something and it's how each user will have it's own data ? it's easy our collection will be the same uid of the currentUser and we need subcollection beceause we have different sections for the notes taken
in Input.js should be an async methode like this
const nametRef = useRef();
const textRef = useRef();
const { currentUser } = useAuth();
const [error, setError] = useState("");
const pushData = async e => {
e.preventDefault();
if (nametRef.current.value === "" && textRef.current.value === "") {
setError("take note");
} else {
setError("");
try {
return await useFireStore
.collection(`${currentUser.uid}`)
.doc("socket")
.collection(`${docs}`)
.add({
noteName: nametRef.current.value,
contentNote: textRef.current.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
});
} catch {
setError("please verify your connection");
}
}
};
it goes the same for fetching data from the firestore as we saved the name of our collection with the same current user id
note that our methode must be async so it will always listen to the change from the server side
const { currentUser } = useAuth();
const [error, setError] = useState("");
const [sockets, setSockets] = useState([]);
const pullData = async () => {
return await useFireStore
.collection(`${currentUser.uid}`)
.doc("socket")
.collection(`${docus}`)
.orderBy("createdAt", "desc")
.onSnapshot(snapshot => {
const data = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
data.length === 0 ? setError("no notes yet") : setError("");
setSockets(data);
});
};
useEffect(() => {
// we use pull effect to ovoid memory leak
pullData();
}, []);
and to delete a document in the jsx we add this code
{sockets.map((socket, index) => {
return (
<Fetched key={index}>
<Div>
<Text>{socket.noteName}</Text>
<Disc>{socket.contentNote}</Disc>
</Div>
<Delete
onClick={() => {
useFireStore
.collection(`${currentUser.uid}`)
.doc("socket")
.collection(`${docus}`)
.doc(`${socket.id}`)
.delete();
}}
/>
</Fetched>
);
})}
{error && <p>{error}</p>}
and voila like that we have a fully functioning to do app with auth and each user have the abilty to see it's own data and delete it
PS: code it not fully explained as I said on top, I am highlighting the important thing i did to make it fully function
Posted on December 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.