Context: I have a custom hook that fetches firestore documents. It watches for document changes, then returns it and the loading state. I'm using this hook in another component.
Problem: Changes to the state values returned by the hook (loading and document) do not trigger the component using the hook to rerender and see the updated values.
My Findings: Other custom hooks work and trigger renders, so there must be something wrong with the useDocument hook. If another hook triggers a rerender, only then will loading finally update. The values of loading and document indeed update as expected within the hook, but a rerender of the component is still never triggered.
Important Notes: useFirebase() is a hook called within useDocument whose state is lifted up into context using the constate library. So technically this hook is a consumer of some provider higher up the tree that keeps track of the firebase libraries. This is to avoid unnecessary network calls.
export function useDocument() {
const { auth, firestore } = useFirebase() // asynchronously fetches firebase modules
const [loading, setLoading] = useState(true)
const [document, setDocument] = useState()
let unsubscribe = null
useEffect(() => {
let unsubscribe = null
const watchDocument = () =>
params?.query.onSnapshot(
(doc) => {
setDocument(doc.data() as T | undefined)
setLoading(false)
},
(err) => {
console.log(err)
setError(err.message)
}
)
if (firestore && auth?.currentUser) {
unsubscribe = watchDocument()
}
return () => {
unsubscribe && unsubscribe()
}
}, [firestore, auth?.currentUser])
return {
document,
loading
}
}
const MyComponent = () => {
const {document, loading} = useDocument()
console.log(loading) // changes to "loading" doesn't trigger rerender of this component
}