[英]Firestore query not getting results when page first loads, but is when page re-renders - React Native
PROBLEM问题
I am trying to receive documents from a collection from firestore when the page loads in.当页面加载时,我正在尝试从 firestore 的集合中接收文档。
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.当我通过点击更改 state 的页面按钮来回忆查询时,它会得到结果。
QUESTIONS问题
Is this an issue with not allowing firebase to initialize?这是不允许 firebase 初始化的问题吗? 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.我有 firebase.js 包含所有数据库代码。
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 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);
}
/* Queries */
/* ----------------------------------------------------- */
//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仪表板.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"), "mcgairns@gmail.com"),
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;
It looks like your issue is on your async useEffect hook.看起来您的问题出在您的异步 useEffect 挂钩上。
UseEffect expects a cleanup function to be or just undefined to be returned. UseEffect 期望返回清理 function 或返回未定义。 When you call your function using the async keyword you are essentially just returning a Promise.当您使用 async 关键字调用 function 时,您实际上只是返回了 Promise。
You can rewrite this as something along these lines so that a Promise is no longer being returned您可以将其重写为沿这些行的内容,以便不再返回 Promise
useEffect(() => {
//Checks if user exists
const getUserInfo = async () => {
user.providerData.forEach((userInfo) => {
setEmail(userInfo.email);
});
}
getUserInfo()
}, [])
I figured it out.我想到了。
I put my application into a loading state.我将我的应用程序放入加载 state 中。 Whilst loading I separated my database calls (one to get user - auth, and the other to get notifications) into two different useEffects.在加载时,我将数据库调用(一个用于获取用户 - auth,另一个用于获取通知)分成两个不同的 useEffects。 I then had a third useEffect that set the loading state to false.然后我有第三个 useEffect 将加载 state 设置为 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]);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.