Firebase auth with React
Tags: react, javascript, fierbase
Published: 2020-12-23 19:43:58

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](https://devdo.netlify.app) I will be highlighting the most important stuff feel free to check the [code](https://github.com/jagarkin/devdo) for more.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wcd6c6l7qd3pevcml9bl.PNG)

let's start by installing our dependencies
```shell
npm install react-icons --save
npm install --save styled-components
npm install react-tabs
npm i firebase
```

this is the tree for the code
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gihjbz5b5xmvfld5gx14.PNG)

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 
```javascript
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
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mz6zcmqkocx8prdz8hpd.PNG)


create an AuthProvider so that we have firebase auth on top 
```javascript
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 
```javascript
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 
```javascript
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
```javascript
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

```javascript
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
```javascript 
{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