wch
wch

Reputation: 304

How to automatically update data after a change

I am making a small application for writing words, using a Firestore Cloud for data storage. I use onSubmit to send data to Firestore for storage.

Everything works and is saved to the cloud, but the data is not updated on the page, for which you need to reload the page and after that the data will already be updated.

How can I solve this problem, do I need to render a new array every time and get data from the server in order to update the data (fetchProduct), or is it possible in some other way?

function Menu() {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const { user } = UserAuth();

  const fetchProduct = async () => {
    const ref = collection(db, "langcards-db");
    const q = query(ref, where("author", "==", user.uid));
    const querySnapshot = await getDocs(q);
    const arr = [];
    querySnapshot.forEach((doc) => {
      arr.push({
        ...doc.data(),
        id: doc.id,
      });
    });
    setData(arr);
    setIsLoading(false);
  };

  useEffect(() => {
    if (user) {
      fetchProduct();
    } else {
      setData([]);
      setIsLoading(false);

    }
  }, []);

  useEffect(() => {
    if (user) {
      fetchProduct();
    } else {
      setData([]);
      setIsLoading(false);

    }
  }, [user]);

  const onSubmit = async (e) => {
    e.preventDefault();
    let rw = word.replace(/\s/g, "");
    let rt = translate.replace(/\s/g, "");
    if (rw.length >= 1 && rt.length >= 1) {
      setWarn(false);
      await addDoc(collection(db, "langcards-db"), {
        word: word,
        translate: translate,
        note: note,
        category: "category",
        author: user.uid,
      });
      setWord("");
      setTranslate("");
      setNote("");
      console.log(data)
    } else {
      setWarn(true);
    }
  };

  return (
    <div className="main-inner">
      {isLoading ? (
        <Loader />
      ) : (
        <div className="content">
           <Routes>
       
          <Route
            path="addcard"
            element={
              <AddCard
                onChangeWord={onChangeWord}
                onChangeNote={onChangeNote}
                onChangeTranslate={onChangeTranslate}
                onSubmit={onSubmit}
                word={word}
                translate={translate}
                note={note}
                warn={warn}
                resetFormAdd={resetFormAdd}
              />
            }
          />
          <Route
            path="saved"
            element={<Saved data={data} setData={setData} />}
          />
        </Route>
      </Routes>
        </div>
  );
}
export default Menu;

Upvotes: 0

Views: 55

Answers (1)

kaiserm99
kaiserm99

Reputation: 313

For this problem you should not use getDocs but onSnapshot which listens for changes in the data. Also, this way you can update the state directly and don`t have to create a new array each time. Then you can directly refer to .data when accessing an entry from the data state.

useEffect(() => {
  const ref = collection(db, "langcards-db");
  const q = query(ref, where("author", "==", user.uid));

  const unsubscribe = onSnapshot(q, { includeMetadataChanges: true }, (querySnapshot) => {

    setData([]); // Empty state

    querySnapshot.forEach((doc) => {
       // Do something with your data (append it to the data array like before)
       setData(old => {...old, {"id" : doc.id, "data" : doc.data()});
    });
  });

    return () => { unsubscribe(); };
  }, [])

In this doc you can read more about how to fetch data from your firestore.

Upvotes: 1

Related Questions