Reputation: 61
Can someone provide some guidance on getting a specific item within a Firestore collection before the rest of the code moves on? I want to get the user item in the users collection before iterating through the reviews collection, and this is best achieved through using async/await as far as I know, but everywhere I look on stack overflow and elsewhere, they achieve it using setups/syntax much different to what I have been using.
Here's what I've got:
import React, { useState, useEffect } from "react";
import { Image, Text, TextInput, TouchableOpacity, View } from "react-native";
import styles from "./model/AccountStyles.js";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { firebase } from "../firebase/config";
export default function AccountScreen({navigation }) {
const [existingReviewsArray, setExistingReviewsArray] = useState([]);
useEffect(() => {
let userID;
//get userID
firebase.auth().onAuthStateChanged((user) => {
const usersRef = firebase.firestore().collection("users");
usersRef
.doc(user.uid)
.get()
.then((document) => {
const data = document.data();
userID = data.id
});
});
//get reviews made by userID to useState
var addToReviewsArray = [];
const reviewsRef = firebase.firestore().collection('reviews');
reviewsRef.get().then((querySnapshot) => {
querySnapshot.forEach(snapshot => {
if (snapshot.data().userID == userID){
var existingReview = snapshot.data();
addToReviewsArray = ([...addToReviewsArray , existingReview]);
}
}
)
setExistingReviewsArray(addToReviewsArray);
});
}, []);
What would be the best way to go about this? Would appreciate any guidance here.
Upvotes: 1
Views: 685
Reputation: 2582
Explanation of the code below
useEffect
hooks are async by design, and the Firebase API is too, so what I try to do clearly with this example is show how to implement a reactive programming approach. I don't use the async/await pattern here. This may also not be the best way of doing things - it's just the first thing that came to mind. :)
The code below "reacts" to the change of the user's auth state because initially the userId
is undefined
:
const [userId, setUserId] = useState(); // this means userId is undefined
The userId
variable is populated in the first useEffect
, which has no dependencies (the empty []
), meaning that it should only run once when the component is mounted.
There is then a second useEffect
hook created to listen to changes in the userId
variable, which runs a function that can then use the newly populated variable.
Here's how I would do it. :)
import { useState, useEffect } from "react";
export default function AccountScreen({ navigation }) {
const [userId, setUserId] = useState();
const [existingReviewsArray, setExistingReviewsArray] = useState([]);
// Create a useEffect [with no dependencies] that runs once to get the userId
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
const usersRef = firebase.firestore().collection("users");
usersRef
.doc(user.uid)
.get()
.then((document) => {
const data = document.data();
// Use the set state hook here to trigger the second useEffect below
setUserId(data.id);
});
});
}, []);
// Create a useEffect that is triggered whenever userId is changed
useEffect(() => {
// get reviews made by userID to useState
var addToReviewsArray = [];
const reviewsRef = firebase.firestore().collection("reviews");
reviewsRef.get().then((querySnapshot) => {
querySnapshot.forEach((snapshot) => {
if (snapshot.data().userID == userID) {
var existingReview = snapshot.data();
addToReviewsArray = [...addToReviewsArray, existingReview];
}
});
setExistingReviewsArray(addToReviewsArray);
});
}, [userId]);
// Use your `existingReviewsArray` in the render
}
Upvotes: 1