CSFrequency / react-firebase-hooks

React Hooks for Firebase.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

useDocumentData fails to update when read permission is not longer denied

amiregelz opened this issue · comments

commented

I'm using useDocumentData in order to fetch a document and keep it updated.

When the hook is initialized, reading the doc is not permitted yet (due to a certain condition in the Firestore Security Rules not being met), therefor the read fails with FirebaseError: Missing or insufficient permissions.

However, after a few minutes there is a change in the database and the document can be read successfully.

If I refresh the page it works properly - otherwise the hook does not automatically update.

How can I fix that? I need it to automatically detect that there are permissions to read this document and keep me up to date with its data.

I think that can be done by writing a query with the ID of the target document as a filter like below.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /tests/{id} {
      allow read: if resource.data.isPrivate == false;
      allow write: if true;
    }
  }
}
import {
  documentId,
  DocumentReference,
  query,
  setDoc,
  where,
} from "firebase/firestore";
import { useCollectionData } from "react-firebase-hooks/firestore";

export const Test = (docRef: DocumentReference) => {
  const [docs] = useCollectionData(
    query(
      docRef.parent,
      where(documentId(), "==", docRef.id),
      where(documentId(), "!=", "93OE3unhtzLf2buLXF3e" /* fake ID */), // hack from https://stackoverflow.com/q/67556515/7923918
      where("isPrivate", "==", false)
    )
  );
  const doc = docs?.[0];

  return (
    <>
      <p>{JSON.stringify(doc) ?? "loading"}</p>
      <button onClick={() => void setDoc(docRef, { isPrivate: false })}>
        update
      </button>
    </>
  );
};

I think it's because of the useEffect dependency used in the code: link, which checks if the query has changed or not inside useDocument(query) before calling onSnapshot (I may be wrong though)

To overcome this issue, you can do something like this:

const query = firestoreChange ? <your query/document reference> : undefined/null;
const [doc, loading, error] = useDocumentData(query);

This will change your query depending on the firestore change and reload fetching
This assumes you have a way of identifying the change in frontend (eg: user sign sign in status)

Otherwise, you can use onSnapshot from firebase directly, and even make a custom hook

const unsubscribe = onSnapshot(
	documentReference, 
	(documentSnapshot) => {
		console.log(documentSnapshot.data());
		setValue(documentSnapshot.data());
		.... etc.
	})

You can read more about onSnapshot here: link

Hopefully this helps