Timothy Lentz
Timothy Lentz

Reputation: 41

React + Firestore : Return a variable from a query

I'm learning React and Firestore currently and am a bit stuck. I'm trying to retrieve a users name from a firestore collection by searching their uid.

The following code is executed in a map of 'lessons' to create a list.

{lesson.post_author && findName(lesson.post_author)}

The following code is the findName function.

let findName = uid => {
    firebase.firestore().collection("users")
      .where('uid', '==', uid)
      .get()
      .then(querySnapshot => {
          console.log(querySnapshot.docs[0].data().name);
    });

  };

Currently, the findName function will console log all of the names to the console successfully. I've altered the code to be able to console log outside of the firestore call, but that returns a promise pending in console.

The goal of the code is to return the name rather then the uid in the list.

Any help would be much appreciated. Thank you!

Upvotes: 4

Views: 3641

Answers (2)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

As others have explained, you can't return that value, since it's loaded from Firestore asynchronously. By the time your return runs, the data hasn't loaded yet.

In React you handle this by putting the data in the component's state, and using it from there. If you do this, your render method can simply pick it up from the state, with something like:

{lesson.post_author && findName(lesson.post_author_name)}

(the above assumes that lesson indirectly comes from the state.

It's a bit easier if we pretend there's only one lesson, and you have these values straight in the state:

{state.post_author && findName(state.post_author_name)}

Now I'll assume you already have the post_author and you just need to look up the author's name. That means that somewhere in/after componentDidMount you'll load the additional data and add it to the state:

componentDidMount() {
  firebase.firestore().collection("users")
    .where('uid', '==', this.state.uid)
    .get()
    .then(querySnapshot => {
      this.setState({ post_user_name: querySnapshot.docs[0].data().name });
  });
}

Now the loading of the data still happens asynchronously, so the call to setState() happens some time after componentDidMount has completed. But React is aware that changing the state may require a refresh of the component, so it responds to the call to setState() by rerendering it.

Note that I'd highly recommend using each user's UID as the ID of the documents in users. That way you don't need a query and can just do a directly lookup:

componentDidMount() {
  firebase.firestore().collection("users")
    .doc(this.state.uid)
    .get()
    .then(doc => {
      this.setState({ post_user_name: doc.data().name });
  });
}

Upvotes: 2

Ronnie Smith
Ronnie Smith

Reputation: 18555

I'm trying to retrieve a users name from a firestore collection by searching their uid.

This is accomplished by using the asyncronous .get method on a Firestore reference. In your case, you probably have a users collection of firebase.auth().currentUser.uid named documents.

var userRef = firebase.firestore().collection('users').doc(users.uid);
userRef.get().then(function(doc) {
    if (doc.exists) {
        console.log("Users first name is:", doc.data().firstName);
    } else {
        // doc.data() will be undefined in this case
        console.log("No such document!");
    }
}).catch(function(error) {
    console.log("Error getting document:", error);
});

Upvotes: 1

Related Questions