0
votes

I have a React app with Firebase backend. I have a users collection in the database which stores the photoURL of the user.

When a user comments on a post, instead of saving that photoURL each time into the comments collection I just want to render the photoURL from the users collection.

That way if the user updates their photoURL it is updated on all the comments plus there's no duplication of data.

On each comment I have saved the uid in the comment collection. I just can't quite figure out how to map through all the comments and take the uid and use that to get the photoURL from the users collection. Below is what I have so far.

I'm new to React so apologies if this is a simple fix.

const [comments, setComments] = useState([])

// This is used to get all the comments
    useEffect(() => {
        let unsubscribe
        if (postId) {
            unsubscribe = db.collection('posts').doc(postId).collection('comments').orderBy('timestamp', 'desc').onSnapshot((snapshot) => {
                setComments(snapshot.docs.map((doc) => doc.data()))
            })
        }
        return () => {
            unsubscribe()
        }
    }, [postId])


// This is for adding the comment to the comments collection
const postComment = (event) => {
        event.preventDefault()

        db.collection('posts').doc(postId).collection('comments').add({
            text: comment,
            username: user.displayName,
            timestamp: firebase.firestore.FieldValue.serverTimestamp(),
            photoURL: user?.photoURL, // This does not save anything because it's taking form auth user and not user collection
            uid: user?.uid
        })
        setComment('')
        setCommentActive(true)
        setCommentsArrow(!commentsArrow)
    }


// This is a function to get the photoURL of any user based on the uid
async function getImageURL(uid) {
     return (await db.collection("users").doc(uid).get()).data().photoURL
}


// Rendering the comments
return (
<div style={{ transition: "height 0.3s linear" }} className={commentActive ? null : "hidden"}>
    <div className="post__comments">
                    
         {comments.map((comment) => (
              <div className="post__comment">
                   <Avatar
                        className="post__avatar"
                           alt=""
                           src={getImageURL(comment.uid)} // Calls the getImageURL function and passes in the uid from the comment
                    />
                    <p><strong>{comment.username}</strong> {comment.text}</p>
              </div>
          ))}
    </div>
</div>
)
1

1 Answers

0
votes

Here are the 2 options that I see are viable:

  1. I see you are storing the users' UID in the comment doc, then make a separate request to Firestore (users collection) and then fetch their photoURL from that document.
  2. This is what I prefer and seems to be the most viable way but to do so you would have to store the user images in Firebase Storage or any storage service. There you can structure your directory like /images/<user_uid>. So if my UID in the comment is 'uid123' then you would look for the image in Firebase Storage.

A download URL from Firebase Storage looks like:

https://firebasestorage.googleapis.com/v0/b/<project_id>.appspot.com/o/users%2F<userId>.png?alt=media&token=token

Now it does has that token at the end so you may have to use the getDownloadURL method or make your bucket public from the Google Cloud Console. But the format of URL will remains consistent i.e. https://domain.tld/path/image.png

This means users can't just simply paste an image URL to update their photo but they'll have to upload the image and you'll have to store it somewhere.

If you don't want to use storage or the 2nd method above, then you would have to make additional calls to the database to get users' profile picture.

Edit: Function to get user's image URL from UID:

async function getImageURL(uid) {
  return (await db.collection("users").doc(uid).get()).data().photoURL
}

Then in the component below:

{comments.map((comment) => (
    <div className="post__comment">
        <Avatar
            className="post__avatar"
            alt=""
            src={getImageURL(comment.uid)}
        />
        <p><strong>{comment.username}</strong> {comment.text}</p>
    </div>
))}