Skip to content
Advertisement

How To Render Data From Firebase Without Page Refresh

I’m creating a simple note taking app. The functionality I need is the ability to make a new LABEL, and then inside that label create a TITLE, with TAGS(notes) associated to that title. Right now I have it all working nicely, except when I submit the new label, and/or new title/tags, I need to refresh to see the newly added data. I’ve used tutorials as well as trial and error to get to this point, and I’m a newly lamented bootcamp graduate so please be patient with me 🙂 Any advice is greatly appreciated. How can I make it so when I “createLabel” or “createCard”, the data is instantly rendered on screen instead of having to refresh my page?

Here’s the code:

import "./App.css";
import { useState, useEffect } from "react";
import React from "react";
// Components
import Header from "./components/Header/Header";
// Firebase
import { db } from "./firebase-config";
import {
  collection,
  getDocs,
  getDoc,
  setDoc,
  doc,
  updateDoc,
  addDoc,
  deleteDoc,
  arrayUnion,
} from "firebase/firestore";
// Clipboard
import { CopyToClipboard } from "react-copy-to-clipboard";

function App() {
  const [newLabel, setNewLabel] = useState("");
  const [labels, setLabels] = useState([]);
  const [activeLabels, setActiveLabels] = useState("");
  const [name, setName] = useState("");
  const [tags, setTags] = useState("");
  const labelCollectionRef = collection(db, "labels");

--- I think I need to add logic to the useEffect maybe? 

  useEffect(() => {
    const getLabels = async () => {
      const data = await getDocs(labelCollectionRef);
      setLabels(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
    };

    getLabels();
  }, []);

  const createLabel = async () => {
    await setDoc(doc(db, "labels", newLabel), { id: newLabel });
  };

  const clickHandler = async (title) => {
    setActiveLabels(title);
  };

  const createCard = async () => {
    await updateDoc(doc(db, "labels", activeLabels), {
      info: arrayUnion({ name: name, tags: tags }),
    });
  };

  // const deleteRef = doc(db, "labels", `${doc.data.id}`)

  const deleteLabel = async (i) => {
    await deleteDoc(doc(db, "labels", activeLabels));
  };

  return (
    <div className="App">
      <Header />
      <main>
        <input
          onChange={(e) => {
            setNewLabel(e.target.value);
          }}
          placeholder="Enter Label Name"
          type="text"
        ></input>
        <button onClick={createLabel}>Create Label</button>

        {labels.map((label, i) => {
          if (activeLabels == label.id) {
            return (
              <>
                <div className="tags__section">
                  <h2
                    key={i}
                    className="tags__title"
                    onClick={() => clickHandler(label.id)}
                  >
                    Label: {label.id}
                    <button
                      onClick={() => deleteLabel(i)}
                      className="tags__delete"
                    >
                      DELETE
                    </button>
                  </h2>
                </div>
                {label.info &&
                  label.info.map((info, i) => {
                    return (
                      <div key={i}>
                        <h1 className="tags__name">Name: {info.name}</h1>
                        <h2 className="tags__tags" type="text">
                          Tags: {info.tags}
                        </h2>
                        <CopyToClipboard text={info.tags}>
                          <button className="tags__clipboard">COPY</button>
                        </CopyToClipboard>
                      </div>
                    );
                  })}
                <div className="tags__add">
                  <input
                    onChange={(e) => setName(e.target.value)}
                    type="text"
                    name="title"
                    placeholder="Add title..."
                  ></input>

                  <textarea
                    onChange={(e) => setTags(e.target.value)}
                    name="tags"
                    type="text"
                    placeholder="Add tags..."
                  ></textarea>
                  <button onClick={createCard}>Create Card</button>
                </div>
              </>
            );
          } else {
            return (
              <h2
                className="tags__title"
                onClick={() => clickHandler(label.id)}
                key={i}
              >
                Label: {label.id}
              </h2>
            );
          }
        })}
      </main>
    </div>
  );
}

export default App;

Advertisement

Answer

There are two ways to retrieve data stored in the Cloud Firestore. What you’re using is getDocs() method which is a method to get the data once. The second one is onSnapshot(); this sets a listener to receive data-change events which means Cloud Firestore will send your listener an initial snapshot of any changes to your documents, collections of documents, or the results of queries. See sample code below on how to implement the onSnapshot() method:

useEffect(() => {
  const getLabels = async () => {
    const colRef = query(collection(db, '<collection-name>'))
    onSnapshot(colRef, (snapshot) => {
      setLabels(snapshot.docs.map(doc => ({
        id: doc.id,
        data: doc.data()
      })))
    })
  }
  getLabels()
}, [])
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement