Introduction into Firestore

In this chapter, we're going to learn how to read and write data from Firestore. We're going to build the first bits of our application: the ability to add, update, and remove songs from our chart.

Writing data to Firestore

Let's replace content of src/App.js with a simple HTML form:

import firebase from "firebase/app";
import React from "react";
import "./App.css";

export default function App() {
  return (
    <div className="App">
      <h1>My Favourite Tame Impala Songs</h1>

      <h2>Add new song:</h2>

      <form name="song" onSubmit={handleSubmit}>
        <p>
          <label>
            Title: <input name="title" required />
          </label>
        </p>

        <p>
          <label>
            Rating:{" "}
            <input name="rating" type="number" min="0" max="100" required />
          </label>
        </p>

        <p>
          <button type="submit">Add to chart!</button>
        </p>
      </form>
    </div>
  );
}

async function handleSubmit(e) {
  e.preventDefault();
  const form = e.target;

  // 1. Get data from the form
  const title = form.title.value;
  const rating = parseInt(form.rating.value);

  // 2. Get Firestore instance
  const firestore = firebase.firestore();

  // 3. Add a document to the songs collection with random id
  const song = await firestore.collection("songs").add({ title, rating });

  alert(`Added ${title} song with id ${song.id}`);
  form.reset();
}

In the handleSubmit handler, we've used Firestore to add entered data as a document to the songs collection:

const firestore = firebase.firestore();

const song = await firestore
  .collection("songs")
  .add({ title, rating });

If we'll open our app in a browser, enter some data and submit the form:

And then open the database explorer on Firebase, you'll see that the document has been added successfully:

Reading data from Firestore

Now, let's display our list. We'll read all documents from the songs collection and display as a list using React Hooks. Update src/App.js:

export default function App() {
  // 1. Create a state to store the songs
  const [songs, setSongs] = useState();
  useEffect(() => {
    // 2. Query all documents in the songs collection
    firebase
      .firestore()
      .collection("songs")
      .get()
      // 3. When the query is resolved, save the documents
      // to the state
      .then(songs => setSongs(songs.docs));
  }, []);

  // The rest of the component...
}

Read data from Firestore in real-time

We've fetched songs from the database, but when you add a new song, you have to refresh the page to see it. Let's use the Firestore real-time feature and listen to the documents instead of fetching them only when the page loads. Add this code the start of our App component in src/App.js:

export default function App() {
  const [songs, setSongs] = useState();
  useEffect(() => {
    return (
      firebase
        .firestore()
        .collection("songs")
        // Pass callback to receive updated songs
        .onSnapshot(songs => setSongs(songs.docs))
    );
  }, []);

  // The rest of the component...
}

Updating documents

Now let's see how to update documents. We're going to add onChange callback where we will update the document:

<ul>
  {songs
    ? songs.map(song => (
        <li key={song.id}>
          {song.data().title}{" "}
          <input
            value={song.data().rating}
            onChange={e => {
              // Update the rating:
              song.ref.update({ rating: parseInt(e.target.value) });
            }}
            type="number"
            min="0"
            max="100"
            required
          />
        </li>
      ))
    : "Loading..."}
</ul>

You might see that the data saved to the database:

Removing documents

Finally, let's add the ability to remove songs. Update our App component in src/App.js:

<button
  onClick={e => {
    e.preventDefault();
    // 1. Confirm the deletion
    const confirmDelete = confirm(`Do you want to remove ${data.input}?`);
    // 2. Remove the component (the delete function returns a promise)
    confirmDelete && song.ref.delete();
  }}
>
  Remove
</button>

In this chapter you've learned how perform basic operations on Firestore. In the next chapters you'll learn how to authenticate users, how to write query and secure the database.

Next chapter:
Learn how to enable authentication using different providers. You'll see how to use Firebase Authentication with React Hooks.