dragi
dragi

Reputation: 1512

Firebase/React query for the user's name

I'm trying to make my Post component work by getting the name of the user who posted it. Right now, the way it works is that I login with a user (through Google or using email/password combo) and I get the data of that user as auth.currentUser.displayName or email, uid etc...

When I make a post, it takes the user's id which is the uid because that is going to be unique.

Now, when I'm loading the posts I get the post.name which was originally the user's name (until I changed it to store the uid instead) but now I get the ID of the user....

So my question is: How can I get the user's name instead of the ID?

This is the structure in my database

As you can see on the picture above, the name in the posts is the ID of the user. I want to get the username of the user when displaying the posts. How can I do that?

I hope it makes some sense..

Here is my render() code:

render() {
    const { message, posts, error } = this.state;
    const isInvalid = message === '';

    return (
        <div>
            <form onSubmit={this.onSubmit}>
                <p>
                    Posting as:{' '}
                    {auth.currentUser.displayName || auth.currentUser.email}
                </p>
                <textarea
                    value={message}
                    onChange={event =>
                        this.setState(byPropKey('message', event.target.value))
                    }
                    name="message"
                    placeholder="Message..."
                />
                <button disabled={isInvalid} type="submit">
                    Post
                </button>

                {error && <p>{error.message}</p>}
            </form>

            <div>
                <ul>
                    {posts.map(post => (
                        <li key={post.id}>
                            <h4>{post.message}</h4>
                            <p>posted by: {post.name}</p>
                            {post.name === auth.currentUser.uid ? (
                                <button
                                    type="submit"
                                    onClick={() => {
                                        database.ref(`/posts/${post.id}`).remove();
                                    }}
                                >
                                    Delete Post
                                </button>
                            ) : null}
                        </li>
                    ))}
                </ul>
            </div>
        </div>
    );
}

The way i'm displaying the posts:

componentDidMount() {
    const postsRef = database.ref('posts');
    postsRef.on('value', snapshot => {
        let posts = snapshot.val();
        let newState = [];
        for (let post in posts) {
            newState.push({
                id: post,
                name: posts[post].name,
                message: posts[post].message
            });
        }
        this.setState({
            posts: newState
        });
    });
}

and the onSubmit:

onSubmit = event => {
    const { message } = this.state;

    db.doCreatePost(auth.currentUser.uid, message)
        .then(() => {
            this.setState({
                message: '',
                error: null
            });
        })
        .catch(error => {
            this.setState(byPropKey('error', error));
        });

    event.preventDefault();
};

Upvotes: 0

Views: 2004

Answers (2)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

You'll need to do a client-side join of the user data. In it's simplest form this can be:

componentDidMount() {
    const postsRef = database.ref('posts');
    const usersRef = database.ref('users');
    postsRef.on('value', snapshot => {
        let posts = snapshot.val();
        let newState = [];
        for (let post in posts) {
          usersRef.child(posts[post].name).once('value').then(function(snapshot) {
            const username = snapshot.val().username;
            newState.push({
                id: post,
                uid: posts[post].name,
                name: username,
                message: posts[post].message
            });
            this.setState({
              posts: newState
            });
          })
        }
    });
}

Note that this code sets the state each time a user name is loaded, so you'll see many updates to the UI. If you want to reduce that number, look into Promise.all() to wait for all reads. You'll also want to keep a cache of users you've already loaded, since right now the code loads a user for each post (even if a single user has many posts).

Upvotes: 1

Alex S&#225;nchez
Alex S&#225;nchez

Reputation: 940

You can get the username like this.

firebase.database().ref('/users/' + post.name).once('value').then(function(snapshot) { const username = (snapshot.val() && snapshot.val().username) })

  1. Use 'post.name' as a reference to the user.
  2. Search in the 'users' collection the exact value that match that user id.
  3. Get 'username' value from the snapshot.

Hope it helps!

Upvotes: 1

Related Questions