I am trying to do the following and cannot seem to get the most suitable solution: On the top level of my React app (App component) I am loading firebase and firestore. I have a react context where my auth info is stored in. The auth context is not immediately loaded but after some time. I am using the onAuthStateChanged (from firebase) to wait for it. My code looks as follows:
const firebase = new Firebase(); //custom class, instantiates firebase
const [authData, setAuthData] = useState({
firebase,
user: null,
isInitializing: true,
userdata: { info: null, data: null }
});
useEffect(() => {
// listen for auth state changes
const unsubscribe = firebase.auth.onAuthStateChanged(async returnedUser => {
//set Auth data into state to pass into context
setAuthData({ ...authData, user: returnedUser, isInitializing: false });
});
// unsubscribe to the listener when unmounting
return () => unsubscribe();
}, []);
Now I want to add a listener to this component to listen for profile data in firebase cloud firestore. They provide an onShapshot function for that.
Where to add that listener? Because I dont want to do too many calls. Can I safely place the listener in the unsubscribe function? How to make sure the listener ubsubscribes when unmounting?
First I tried with an additional useEffect hook, like this:
useEffect(() => {
if (authData.isInitializing || authData.user === null) return;
const ref = firebase.db.doc("/env/" + process.env.REACT_APP_FIRESTORE_ENVIRONMENT + "/users/" + authData.user.uid);
return ref.onSnapshot(doc => {
setAuthData({ ...authData, userinfo: doc.data() });
});
}, []);
This doesnt work because it only runs once (on mount), and then it just returns nothing because it is still initializing, and I cannot set it to run on every update because then it keeps querying firestore, updating state, and query (endless loop).
Passing down the state in the context works and I can use it anywhere (auth state). I just want to be able to have the basic user data in context. Now, I could add this manually (when user logs in, get the user profile + data and store in state), but I want to handle updates on this data as well, so I need the onSnapshot listener. How to make sure I call the listener only once?