[英]React useEffect is returning empty data when page loads for the first time
[英]Firestore query not getting results when page first loads, but is when page re-renders - React Native
问题
当页面加载时,我正在尝试从 firestore 的集合中接收文档。
尽管运行查询没有错误(加载两次),但它返回时没有结果。 当我通过点击更改 state 的页面按钮来回忆查询时,它会得到结果。
问题
这是不允许 firebase 初始化的问题吗? 如何使查询在页面加载时起作用,以便它可以使用数据库中的信息进行呈现?
关于我的代码
我有 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 };
仪表板.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;
看起来您的问题出在您的异步 useEffect 挂钩上。
UseEffect 期望返回清理 function 或返回未定义。 当您使用 async 关键字调用 function 时,您实际上只是返回了 Promise。
您可以将其重写为沿这些行的内容,以便不再返回 Promise
useEffect(() => {
//Checks if user exists
const getUserInfo = async () => {
user.providerData.forEach((userInfo) => {
setEmail(userInfo.email);
});
}
getUserInfo()
}, [])
我想到了。
我将我的应用程序放入加载 state 中。 在加载时,我将数据库调用(一个用于获取用户 - auth,另一个用于获取通知)分成两个不同的 useEffects。 然后我有第三个 useEffect 将加载 state 设置为 false。 这允许在页面呈现完整页面之前使用数据设置状态。
//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.