DEV Community

Antoine CHEVALIER
Antoine CHEVALIER

Posted on

 

How to make a CRUD application with Firestore and React.

Table of content :

  • Setup Firebase
  • Update Firestore rules
  • Post
  • Get
  • Delete

Setup Firebase

You can import the firebase settings from Project Settings inside your firebase application. I will only suggest you to store the values of the given config into a .env file for security reason. (We don’t want to let anyone access our firebase application).

import { getFirestore } from ‘firebase/firestore’;
import { initializeApp } from “firebase/app”;

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain:  process.env.REACT_APP_AUTH_DOMAIN,
  databaseURL:  process.env.REACT_APP_DATABASE_URL,
  projectId:  process.env.REACT_APP_PROJECT_ID,
  storageBucket:  process.env.REACT_APP_STORAGE_BOCKET,
  messagingSenderId:  process.env.REACT_APP_MESSAGING_SENDER,
  appId:  process.env.REACT_APP_APP_ID,
  measurementId:  process.env.REACT_APP_MEASUREMENT_ID
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
export { db, app };
Enter fullscreen mode Exit fullscreen mode

The only difference between the default config is that we initialized the Firestore db.

Update Firestore Rules

Firestore got a defined rule that only allow us to write inside a document named like our userID. To do so we need a userID, received when login in. But we are not dealing with auth today so we need to change this rule.

Initial Rules :

service cloud.firestore {
  match /databases/{database}/documents {
    match /{userId}/{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Simplify rules :

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Post

We can then process to the creation of new users.

import { db } from “./firebase”;
import { setDoc, doc  } from “firebase/firestore”;
  const createUser = async (name, age) => {
    try {
    const mockUserId = name + age
      await setDoc(doc(db, “users”, mockUserId), {
        name,
        age,
      });
    } catch (e) {
      console.log(e);
    }
  };
Enter fullscreen mode Exit fullscreen mode

DB : Reference to our Firestore Database that we exported during the setup process.

A Doc : A document is a lightweight record that contains certains fields. Data-type : Object

A Collection : A collection is a container of documents. Data-type : Array

We create a function that take as an argument the name and the age of the user. We then call the setDoc function.“users” is the name of the collection that will contains our users. mockUserId is the id of our user table.

Get

Now let’s get the list of our users.

  const getUsers = async () => {
    try {
      const usersRef = collection(db, “users”);
      const usersSnap = await getDocs(usersRef)
      const users = [];
      usersSnap.forEach(user => users.push(user.data()));
      return users;
    } catch (e) {
      console.log(e);
    }
  }
Enter fullscreen mode Exit fullscreen mode

We select the collection users, then get the docs of this collection. We then create a list of users. And for each documents we add their data to the list of users and return it.

Delete

  const deleteUser = async (userID) => {
    try {
      const userRef = doc(db, “users”, userID);
      await deleteDoc(userRef)
    } catch (e) {
      console.log(e);
    }
  }
Enter fullscreen mode Exit fullscreen mode

To delete a user we need their reference ID in the collection. So we get it and create a ref of the document, and call the deleteDoc function.

import "../common/style/index.css";
import Navbar from "../common/components/NavBar";
import { db } from "../common/firebase";
import { setDoc, doc, deleteDoc, getDocs , collection } from "firebase/firestore";
import { useEffect, useState } from "react";

function App() {
  const [newUser, setNewUser] = useState();
  const [users, setUsers] = useState([])

  const createUser = async (name, age) => {
    try {
      await setDoc(doc(db, "users", name + age), {
        name,
        age,
      });
    } catch (e) {
      console.log(e);
    }
  };

  const getUsers = async () => {
    try {
      const usersRef = collection(db, "users");
      const usersSnap = await getDocs(usersRef)
      const users = [];
      usersSnap.forEach(user => users.push(user.data()));
      return users;
    } catch (e) {
      console.log(e);
    }
  }

  const deleteUser = async (userID) => {
    try {
      const userRef = doc(db, "users", userID);
      await deleteDoc(userRef)
    } catch (e) {
      console.log(e);
    }
  }

  const handleDeleteUser = async (userRef) => {
    try {
      await deleteUser(userRef);
      setUsers(await getUsers());
    } catch (e) {
      console.log(e);
    }
  }

  useEffect(() => {
    (async() => setUsers(await getUsers()))()
  }, [])

  const handleCreateUser = async (e) => {
    e.preventDefault();
    createUser(newUser.name, newUser.age);
    setUsers(await getUsers());
  };

  return (
    <div className="App">
      <form className="form" onSubmit={(e) => handleCreateUser(e)}>
        <div className="group">
          <input
            type="text"
            required
            minlength="3"
            placeholder="Name..."
            onChange={(e) =>
              setNewUser({
                ...newUser,
                name: e.target.value,
              })
            }
          />
          <span className="highlight"></span>
          <span className="bar"></span>
        </div>

        <div className="group">
          <input
            type="text"
            placeholder="Age..."
            required
            onChange={(e) =>
              setNewUser({
                ...newUser,
                age: e.target.value,
              })
            }
          />
          <span className="highlight"></span>
          <span className="bar"></span>
        </div>
        <button className="button">Create User</button>
      </form>
     {users.length > 1 && users.map((user, index) => {
      return (
        <div key={index}>
          {" "}
          <h1>Name: {user.name}</h1>
          <h1>Age: {user.age}</h1>
          <button
          onClick={() => handleDeleteUser(user.name + user.age)}
          >
            X
          </button>
        </div>
      );
    })}
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

End

Thanks for reading this article. - Antoine

Here’s a link to the Github application

Top comments (2)

Collapse
 
oldault profile image
Simon Vernier

Where can I Update Firestore Rules?

Firestore got a defined rule that only allow us to write inside a document named like our userID. To do so we need a userID, received when login in. But we are not dealing with auth today so we need to change this rule.

I can't seem to find the folder. And whenever I paste:

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Inside my config folder, I get an error telling me "service" is not recognized.

Collapse
 
seyboo profile image
Antoine CHEVALIER • Edited

Access to the Cloud Firestore tab inside firebase and select rules.

Top Posts from the React Ecosystem

1. Changes In The Official React Documentation

The former React Docs Beta has been officially released as the updated React documentation at react.dev after years of hard work and refinement. Check out the brand new React Docs: What’s New in the Updated React Docs

2. CRA's Time is Over

React developer team has removed create-react-app (CRA) from official documentation rendering it no longer the default setup method for new projects. The bulky setup, slow, and outdated nature of CRA led to its removal: create-react-app is officially dead

3. How to Fetch Dev.to Articles for Your Portfolio

Integrate the articles of your Dev.to profile into your personal portfolio with either React, Vue, or Next.js by following these simple steps. It outlines how to include frontend to pull the information and correctly utilizes the Dev.to API: How to Fetch Your Dev.to Articles for Your Portfolio with React