How to make a CRUD application with Firestore and React.
Tags: firebase, react, webdev, beginners
Published: 2022-12-03 13:27:12

## 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 };
```
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;
    }
  }
}
```

Simplify rules : 

```
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}
```

### 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);
    }
  };
```

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);
    }
  }
```

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);
    }
  }
```

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;

```

### End

Thanks for reading this article. - Antoine

Here’s a [link to the Github application](https://github.com/SeyBoo/crud-firebase)