useDocumentData fails to update when read permission is not longer denied
amiregelz opened this issue · comments
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