Firebase only fetches data on second or third attempt

I'm building an app with React and Firestore.

In one feature, I need to use some specific user data to query data from another collection, and show that on the app.

Specifically I want to use users.books, which returns an array, to query the collection books.

However, for some reason the users.books doesn't load on first render. It typically takes 2-3 renders to fetch the books.user data. This is despite the currentUserUID being loaded right away.

I've tried using a loading state as specified in How to wait for Firebase data to be fetched before progressing?, but to no avail.

Do I need to use the onSnapShot method?

Thanks for reading

My code

import 'firebase/firestore'

import { booksRef} from '../../App';

const ProfileScreen = ({ navigation }) => {
  const currentUserUID = firebase.auth().currentUser.uid;
  const [firstName, setFirstName] = useState('');
  const [userBookTitles, setUserBookTitles] = useState([]);
  const [userBooks, setUserBooks] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function getUserInfo(){
      let doc = await firebase
      .firestore()
      .collection('users')
      .doc(currentUserUID)
      .get();
      
      if (!doc.exists){
        Alert.alert('No user data found!')
      } else {
        let dataObj = doc.data();
        setFirstName(dataObj.firstName)
        setUserBookTitles(dataObj.books)
        console.log(userBookTitles)
      }
    }
    getUserInfo();
  }, [])

  useEffect(() => {
    async function getUserBooks() {
    booksRef.where("title", "in", userBookTitles).onSnapshot(snapshot => (
    setUserBooks(snapshot.docs.map((doc) => ({id: doc.id, ...doc.data()})))
    ))
  }
  setLoading(false);
  getUserBooks()
  }, [])


      if (!loading) {
      return (
          <View style={styles.container}>
            <Text> Hi {firstName} </Text>
            <TouchableOpacity onPress={handlePress}>
            
              <Text> Log out </Text>
            </TouchableOpacity>
            <Row
                    books={userBooks}
            />
          </View>
      );  
    } else { 
      return (
        <View style={styles.container}>
          <Text> Test </Text>
        </View>
    );
    }
  };

1 answer

  • answered 2021-09-27 17:57 Kerron

    So it's worth noting that your setX methods may, or may not, complete in the sequence you have them in your code. Therefore, your booksRef call could be being made even though userBookTitles is an empty array. Which would explain why you're not getting any data on load.

    You're setting userBookTitles in your first useEffect and the only other place I see you're using it is in your booksRef call. One easy fix would be to simple move booksRef inside the else statement of the first useEffect and simply pass it the userBookTitles there. This should help in solving your issue, if I understood it correctly.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum