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 on

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

Top Heroku Alternatives (For Free!)

Recently Heroku shut down free Heroku Dynos, free Heroku Postgres, and free Heroku Data for Redis on November 28th, 2022. So Meshv Patel put together some free alternatives in this classic DEV post.