繁体   English   中英

Firestore 查询在页面首次加载时没有得到结果,但在页面重新呈现时 - React Native

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM