PROBLEM I am trying to receive documents from a collection from firestore when the page loads in.
Despite running the query with no errors (twice on load), it comes back with no results. When I recall the query by hitting a page button that changes a state, it then gets results.
QUESTIONS Is this an issue with not allowing firebase to initialize? How do I make it so that the query works when the page loads so that it can render with information from the database?
ABOUT MY CODE
I have firebase.js which houses all the database code.
I have a dashboard that calls the query and sets the results as states and then passes them to child components to render. When the page loads, I get no results despite the number of times I call it. It's only when I give it some time and recall it, I get results.
firebase.js
import { initializeApp } from "firebase/app";
import {
getFirestore,
collection,
getDocs,
query,
where,
onSnapshot,
} from "firebase/firestore";
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";
/* CONFIG */
/* ----------------------------------------------------- */
// Your web app's Firebase configuration
const firebaseConfig = {
};
// init firebase app
let app;
if (firebase.apps.length === 0) {
app = firebase.initializeApp(firebaseConfig);
} else {
app = firebase.app();
}
// init services
const db = getFirestore();
// init auth
const auth = firebase.auth();
/* Collection References */
/* ----------------------------------------------------- */
// Notifications
export function setCollection(collectionName) {
return collection(db, collectionName);
}
/* Querries */
/* ----------------------------------------------------- */
//Create query by referencing users email
export function setQueryByEmail(collectionRef, email) {
return query(collectionRef, where("user", "==", email));
}
/* Gets JSON Object */
/* ----------------------------------------------------- */
//This query gets the documents within a collection
export function queryDatabase(query, setter) {
let docArray = []; //Stores the documents
getDocs(query)
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
docArray.push({ ...doc.data(), id: doc.id });
});
})
.catch((err) => {
console.log(err.message);
});
setter(docArray); //Sets a setState for the array of documents
}
//Exports
export { firebase, db, getAuth, auth, createUserWithEmailAndPassword };
Dashboard.js
import {
View,
Text,
ImageBackground,
Image,
StyleSheet,
SafeView,
ActivityIndicator,
} from "react-native";
import React, { useState, useEffect } from "react";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { auth } from "./../../firebase.js";
import Navbar from "./Navbar.js";
import ContentBoard from "./ContentBoard.js";
import { navigation } from "@react-navigation/native";
import {
colRefNotifications,
setQueryByEmail,
queryDatabase,
setCollection,
} from "./../../firebase.js";
//Images
const logo = require("../../assets/brain.png");
const title = require("../../assets/title.png");
const background = require("../../assets/background_v1.png");
const Dashboard = ({ navigation }) => {
const [notificationQuantity, setNotificationQuantity] = useState(0);
const [email, setEmail] = useState("");
const [tabID, setTabID] = useState(2);
const [notifications, setNotifications] = useState([]);
const [test, setTest] = useState([]); //Delete
const [loading, setLoading] = useState(true);
let user = auth.currentUser;
let render = 0;
//On first load
useEffect(async () => {
//Checks if user exists
if (user != null) {
console.log("User is not null");
//Gets users email
user.providerData.forEach((userInfo) => {
setEmail(userInfo.email);
});
}
}, []);
//Once user is set
useEffect(() => {
getNotifications();
setLoading(false);
console.log("render:", (render = 1));
}, [email, loading]);
//Gets users notifications
function getNotifications() {
//Create collection reference, query for users notifications, and setting setNotification with array of JSON objects
queryDatabase(
setQueryByEmail(setCollection("relationships"), "[email protected]"),
setTest
);
console.log("Test: ", test);
queryDatabase(
setQueryByEmail(setCollection("notifications"), email),
setNotifications
);
}
//Changes tab id
function changeTab(id) {
setTabID(id);
}
//Shows loading spinner
if (loading)
return (
<View style={{ flex: 1, justifyContent: "center" }}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
//loads page
else
return (
<View style={{ flex: 1 }}>
<ImageBackground source={background} style={styles.backgroundImg}>
<View style={(styles.top, { flex: 0.05 })}></View>
<View style={{ flex: 0.85 }}>
<ContentBoard
activeBtn={tabID}
email={email}
notifications={notifications}
navigation={navigation}
/>
</View>
<View style={{ flex: 0.15 }}>
<Navbar activeBtn={tabID} onPress={changeTab} />
</View>
</ImageBackground>
</View>
);
};
const styles = StyleSheet.create({
backgroundImg: {
display: "flex",
flex: 1,
width: null,
height: null,
},
});
export default Dashboard;
CodePudding user response:
It looks like your issue is on your async useEffect hook.
UseEffect expects a cleanup function to be or just undefined to be returned. When you call your function using the async keyword you are essentially just returning a Promise.
You can rewrite this as something along these lines so that a Promise is no longer being returned
useEffect(() => {
//Checks if user exists
const getUserInfo = async () => {
user.providerData.forEach((userInfo) => {
setEmail(userInfo.email);
});
}
getUserInfo()
}, [])
CodePudding user response:
I figured it out.
I put my application into a loading state. Whilst loading I separated my database calls (one to get user - auth, and the other to get notifications) into two different useEffects. I then had a third useEffect that set the loading state to false. This allowed the states to be set with data before the page rendered the complete page.
//On first load get user data
useEffect(() => {
const getUserInfo = async () => {
await user.providerData.forEach((userInfo) => {
setEmail(userInfo.email);
});
};
//Checks if user exists
if (email == "") {
getUserInfo();
}
}, []);
//When user data has been received get notifications
useEffect(() => {
//Gets users notifications
async function getNotifications() {
console.log("email: ", email);
await queryDatabase(
setQueryByEmail(setCollection("notifications"), email),
setNotifications
); //Create collection reference, query for users notifications, and setting setNotification with array of JSON objects
}
getNotifications();
}, [email]);
//When notifications is set
useEffect(() => {
setNotificationQuantity(notifications.length); //Sets the amount of notifications displayed in the red circle
setLoading(false);
}, [notifications]);