Search

React App with Firebase Authentication & CRUD Operations

post-title

Introduction:

In the world of web development, building applications with robust authentication and database operations is crucial. Firebase, Google's mobile and web application development platform, offers a comprehensive set of tools for building such applications with ease. In this blog, we'll explore how to integrate Firebase Authentication with a React.js frontend and perform CRUD (Create, Read, Update, Delete) operations on a Firebase Realtime Database.

In the ever-evolving landscape of app development, staying ahead requires a blend of innovation, efficiency, and reliability. Amidst this dynamic environment, Firebase emerges as a beacon of technological advancement, offering a comprehensive suite of tools and services that redefine the boundaries of what's possible in app development.

 

Firebase, developed by Google, is a platform that empowers developers to build high-quality applications swiftly and effortlessly, while also ensuring seamless scalability and robust performance. From real-time database management to effortless authentication, cloud messaging, and beyond, Firebase encompasses a plethora of features designed to streamline the development process and enhance the user experience.

 

Unraveling the Benefits of Firebase:

  • Real-Time Database: Firebase's real-time database is a game-changer, providing developers with a cloud-hosted NoSQL database that synchronizes data in real-time across all connected clients. This capability enables the creation of dynamic and interactive applications, fostering engaging user experiences.

 

  • Authentication: Seamlessly integrating authentication into your app is crucial for user security and personalization. Firebase Authentication offers hassle-free authentication methods, including email/password, social media logins, and phone number authentication, ensuring a frictionless login experience for users.

 

  • Cloud Firestore: As a flexible and scalable database solution, Cloud Firestore simplifies data storage and synchronization across devices. Its real-time synchronization and offline support enable developers to build responsive applications that work seamlessly across various platforms and network conditions.

 

  • Cloud Functions: Firebase's serverless compute platform, Cloud Functions, empowers developers to run backend code without managing servers. This capability enables the creation of event-driven applications with ease, allowing for automated processes, notifications, and integrations.

 

  • Hosting and Content Delivery: With Firebase Hosting, deploying web apps and static content is a breeze. Its global content delivery network ensures fast and reliable delivery of content to users worldwide, optimizing performance and enhancing the user experience.

 

  • Cloud Messaging: Engaging users through timely and personalized notifications is essential for app success. Firebase Cloud Messaging enables targeted messaging across platforms, keeping users informed and engaged throughout their journey.

 

  • Analytics and Performance Monitoring: Understanding user behavior and app performance is vital for optimizing user experiences and driving app growth. Firebase Analytics and Performance Monitoring provide valuable insights into user engagement, app performance, and potential bottlenecks, empowering developers to make data-driven decisions.

 

  • Machine Learning and AI: Leveraging the power of machine learning and artificial intelligence can elevate app functionality to new heights. Firebase's integration with Google's ML Kit and TensorFlow Lite enables developers to incorporate intelligent features such as image labeling, text recognition, and smart replies into their applications effortlessly.

 

 

In this tutorial, we'll create a React application integrated with Firebase for authentication and perform CRUD (Create, Read, Update, Delete) operations using Firebase Firestore. We'll start from scratch, assuming you have Node.js and npm installed.
 

Step 1: Setting Up the Project

First, let's create a React application using Create React App:

npx create-react-app firebase-crud

cd firebase-crud 

 

Step 2: Setting Up Firebase

To integrate Firebase into our React app, we need to install the Firebase SDK. Let's install it using npm:

npm install firebase 

 

Step 3: Firebase Configuration

Now, let's configure Firebase in our project. Create a file named firebase.js in the src directory and add the following code:


firebase.js:

import { initializeApp } from "firebase/app";

import { getAuth } from "firebase/auth";

import { getFirestore } from "firebase/firestore";

import { getStorage } from "firebase/storage";



const firebaseConfig = {

    apiKey: YOUR_FIREBASE_APIKEY,

  authDomain: YOUR_AUTHDOMAIN,

  projectId: YOUR_PROJECT_ID,

  storageBucket: YOUR_STORAGE_BUCKET,

  messagingSenderId: YOUR_MESSAGING_SENDER_ID,

  appId: YOUR_APP_ID,

};



export const app = initializeApp(firebaseConfig);

export const auth = getAuth();

export const db = getFirestore(app);

export const storage = getStorage(app);

 

The values required for firebaseConfig can be obtained from the Firebase Console after creating a new project. Here's a step-by-step guide on how to fetch these values:

 

Firebase Console: Visit the Firebase Console at https://console.firebase.google.com/.

 

Create a New Project: If you haven't already, create a new project by clicking on the "Add project" button.

 

Project Settings: Once your project is created, click on the gear icon (settings) next to "Project Overview" in the left sidebar to access project settings.

 

General Settings: In the project settings, you'll find various tabs. Click on the "General" tab.

 

Your Apps: Scroll down to the "Your apps" section. If you haven't already added any apps, you'll see an option to add a web app. Click on it.

 

Register Your App: Register your app by providing a nickname for identification (e.g., "My App").

 

Retrieve Configuration: After registering your app, Firebase will provide you with a snippet containing the configuration object (firebaseConfig) similar to the one you provided in your question.

 

Copy Configuration Values: Copy the values provided for apiKey, authDomain, projectId, storageBucket, messagingSenderId, and appId. These are the values you'll need to replace YOUR_FIREBASE_APIKEY, YOUR_AUTHDOMAIN, YOUR_PROJECT_ID, YOUR_STORAGE_BUCKET, YOUR_MESSAGING_SENDER_ID, and YOUR_APP_ID respectively in your firebaseConfig object.

 

Use in Your Project: Once you have copied these values, you can paste them into your project's firebase.js file or wherever you're initializing Firebase.

 

Step 4: Authentication

We'll implement user authentication using Firebase Auth. Let's create a component for user authentication.

src/components/Auth.js

Sign in with Google:

 

const signInWithGoogle = () => { 

const provider = new firebase.auth.GoogleAuthProvider();

  auth.signInWithPopup(provider)

    .then((result) => {

      // Successful sign-in

      const user = result.user;

      console.log("Google sign-in successful:", user);

    })

    .catch((error) => {

      // Error handling

      console.error("Google sign-in error:", error);

    });

};

 

Sign in with Facebook:

const signInWithFacebook = () => {

 const provider = new firebase.auth.FacebookAuthProvider();

  auth.signInWithPopup(provider)

    .then((result) => {

      // Successful sign-in

      const user = result.user;

      console.log("Facebook sign-in successful:", user);

    })

    .catch((error) => {

      // Error handling

      console.error("Facebook sign-in error:", error);

    });

};

 

Sign in with Twitter

 

const signInWithTwitter = () => {

  const provider = new firebase.auth.TwitterAuthProvider();

  auth.signInWithPopup(provider)

    .then((result) => {

      // Successful sign-in

      const user = result.user;

      console.log("Twitter sign-in successful:", user);

    })

    .catch((error) => {

      // Error handling

      console.error("Twitter sign-in error:", error);

    });

};

 

Sign in with GitHub

const signInWithGitHub = () => {

  const provider = new firebase.auth.GithubAuthProvider();

  auth.signInWithPopup(provider)

    .then((result) => {

      // Successful sign-in

      const user = result.user;

      console.log("GitHub sign-in successful:", user);

    })

    .catch((error) => {

      // Error handling

      console.error("GitHub sign-in error:", error);

    });

};

 

Sign in with Email/Password

 

const signInWithEmailAndPassword = (email, password) => {

  auth.signInWithEmailAndPassword(email, password)

    .then((userCredential) => {

      // Successful sign-in

      const user = userCredential.user;

      console.log("Email/password sign-in successful:", user);

    })

    .catch((error) => {

      // Error handling

      console.error("Email/password sign-in error:", error);

    });

};

 

Step 5: CRUD Operations

Now, let's create components for CRUD operations

src/components/CRUD.js

import { db } from "../firebase";

 

Step 1: Read (Fetch Items from Firestore)

 

const CRUD = () => {

  const [items, setItems] = useState([]);         

  useEffect(() => {

    const fetchItems = async () => {

      try {          

        const querySnapshot = await db.collection("items").get();

        const fetchedItems = querySnapshot.docs.map((doc) => ({

          id: doc.id,

          ...doc.data(),

        }));          

        setItems(fetchedItems);

      } catch (error) {

        console.error("Error fetching items:", error);

      }                 

    };                  

                        

    fetchItems();

  }, []);             

  // Render items...

};

 

Step 2: Create (Add Item to Firestore)

const CRUD = () => {

  // State for input value

  const [newItem, setNewItem] = useState("");

// Add more field for store data

  const addItem = async () => {

    try {

      await db.collection("items").add({ name: newItem });

      // After adding, refetch items to update the UI

      const querySnapshot = await db.collection("items").get();

      const updatedItems = querySnapshot.docs.map((doc) => ({

        id: doc.id,

        ...doc.data(),

      }));

      setItems(updatedItems);

      setNewItem(""); // Clear input field

    } catch (error) {

      console.error("Error adding item:", error);

    }

  };



  // Render input field and add button...

};                    

 

Step 3: Update (Update Item in Firestore)

 

const CRUD = () => {

  const updateItem = async (id, newName) => {

    try {

      await db.collection("items").doc(id).update({ name: newName });

      // After updating, refetch items to update the UI

      const querySnapshot = await db.collection("items").get();

      const updatedItems = querySnapshot.docs.map((doc) => ({

        id: doc.id,

        ...doc.data(),

      }));

      setItems(updatedItems);

    } catch (error) {

      console.error("Error updating item:", error);

    }

  };



  // Render items with update button...

};

 

Step 4: Delete (Delete Item from Firestore)

 

const CRUD = () => {

  const deleteItem = async (id) => {

    try {

      await db.collection("items").doc(id).delete();

      // After deleting, refetch items to update the UI

      const querySnapshot = await db.collection("items").get();

      const updatedItems = querySnapshot.docs.map((doc) => ({

        id: doc.id,

        ...doc.data(),

      }));

      setItems(updatedItems);

    } catch (error) {

      console.error("Error deleting item:", error);

    }

  };



  // Render items with delete button...

};

 

Firebase Storage is a powerful service provided by Firebase that allows developers to store and serve user-generated content, such as images, videos, and audio files, in the cloud. It offers secure and reliable file storage with built-in scalability and accessibility features.

 

const uploadImage = (file) => {

  // Generate a unique name for the file using the current timestamp and its original name

  const name = new Date().getTime() + file.name;

  // Get a reference to the file in Firebase Storage

  const storageRef = ref(storage, name);

  // Upload the file to Firebase Storage

  const uploadTask = uploadBytesResumable(storageRef, file);

  // Listen for upload state changes

  uploadTask.on(

    "state_changed",

    (snapshot) => {

      // Handle upload progress

      const progress_upload = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;

      console.log("Upload is " + progress_upload + "% done");

      switch (snapshot.state) {

        case "paused":

          console.log("Upload is paused");

          break;

        case "running":

          console.log("Upload is running");

          break;

        default:

          break;

      }

    },

    (error) => {

      // Handle errors during upload

      console.error("Error uploading file:", error);

    },

    () => {

      // Once the upload is complete, get the download URL of the uploaded file

      getDownloadURL(uploadTask.snapshot.ref)

        .then((downloadURL) => {

          // Use the download URL for further processing or display

          console.log("File uploaded successfully. Download URL:", downloadURL);

          return downloadURL;

        })

        .catch((error) => {

          console.error("Error getting download URL:", error);

        });

    }

  );

};

 

Generating File Name: The function generates a unique name for the file by concatenating the current timestamp with its original name. This ensures that each file uploaded to Firebase Storage has a unique identifier.

 

Storage Reference: It creates a reference to the file in Firebase Storage using the generated file name.

 

Uploading File: The uploadBytesResumable function is used to upload the file to Firebase Storage. This function allows for the resumption of interrupted uploads and supports large files.

 

Upload State Changes: The function listens for state changes during the upload process. It logs the upload progress as a percentage and handles different states such as paused or running.

 

Completion Callback: Once the upload is complete, the function retrieves the download URL of the uploaded file using the getDownloadURL function. This URL can then be used to access the uploaded file from any location.

 

Error Handling: The function also includes error handling to catch any errors that may occur during the upload process and log them for debugging purposes.



In this tutorial, we've built a React application integrated with Firebase for authentication and performed CRUD operations using Firebase Firestore. We covered setting up Firebase, implementing user authentication, and creating components for CRUD operations. Feel free to customize and expand upon this application to suit your needs.

Happy coding!