0

I have created a helper function for grabbing a user's name.

export function getUserName (userId) {
    if (userId) {
        let firstName;
        let lastName;
        db.collection("users").where("uid", "==", userId)
        .get()
        .then(function(querySnapshot) {
            querySnapshot.forEach(function(doc) {
                console.log(doc.id, "=>", doc.data());
                firstName = doc.data().firstName;
                lastName = doc.data().lastName;
                console.log("firstName: " + firstName)
                console.log("lastName: " + lastName)
            })
        });
        return (<p>{firstName + " " + lastName}</p>)
    }
}

In the console I see the names come through, but not in the return statement. My guess is that the .then hasn't returned and in the meantime, the return has sent the undefined values back to the browser.

Wonder how to avoid this and keep the idea of having a few helper functions I can call for things like displayName, Avatar, etc.

Thanks for any guidance!

ppedrazzi
  • 787
  • 2
  • 10
  • 23
  • Why is your users collection not using uid as the document ID? That's very common, and will make the work of this function a lot easier. UIDs should be unique, at least those assigned by Firebase Authentication. – Doug Stevenson Nov 17 '19 at 02:32
  • Good idea, I was letting FB create the random doc ID and setting UID as a property, but I guess when I create the user in firebase I should use the UID from auth. Do I have that right? – ppedrazzi Nov 17 '19 at 02:35
  • I can see my query being simpler, to your point. Something like db.collection("users").doc(userId). – ppedrazzi Nov 17 '19 at 02:41
  • That's the most common case. It will make everything easier, especially your security rules. – Doug Stevenson Nov 17 '19 at 02:41

1 Answers1

0

You're correct - then() is asynchronous and returns immediately before the result is known. That's how all methods that return promises work in JavaScript.

Instead of trying to return the result synchronously (directly) from the function, you should return another promise that resolves with the data you want the caller the have. The caller can use then() on it and receive the data whenever it becomes available.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Makes sense, but a bit above my pay grade - I need to dive into promises. I currently call this function from another component as {getUserName(item.createdBy)}. Not sure how I would adapt that with promises. – ppedrazzi Nov 17 '19 at 02:43
  • If you don't return a promise in this case, and make the caller use then() to access the final data, you're essentially going down a road with no destination. Understanding promises is absolutely crucial to writing effective JavaScript. See also https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – Doug Stevenson Nov 17 '19 at 02:48