Using the previous implementation, in this lesson we will retrieve the user name for each message as needed in our user interface and subscribe to updates.
Lecturer: [0:00] down here to this messages.map, which is rendering through all of the messages and showing HTML for each message. I'm going to wrap this message.content and its own div.
[0:10] Above that div, I'm going to make a span and I'm going to say the class name is styles.user. Again, if you use my CSS from the GitHub project for this, you'll already have this set. Then inside of that, I want to get the username for this message.
[0:27] What I'm going to do is I'm going to say users.message.userID. Actually, this will be user_ ID. This will look up the user for this message. Then, I'm going to say, .username to get the username for this user.
[0:47] Now, the only problem with this is this may not work if the person who wrote this message doesn't have a username set. Remember, when we created our current user, we didn't have a username set either, so we need to handle that use case.
[1:00] The way that I'll do this is by just copying my code for a second, making a new function called username. I'll just pass in message.user_ID into this. This username function, which I'll define up here, so username, which the function that just takes the user ID. This is just going to check for the username here.
[1:22] In fact, I'll just make a new variable called user, which will be the user inside of the user's object, based on their user ID. I'll say, return user.username using a ternary statement if it set. Return user.username if it's available, otherwise, return the user ID.
[1:48] This isn't a great solution because sometimes the ID is something you want to keep public, so you may want to change this to something like, no username set. You may even just want to give people default usernames. There's a couple different ways to handle this problem.
[2:03] For now, I think the user ID should be just fine. If I refresh the page, you can see there's still an error here. It actually says, "Cannot read property, username of undefined." That's because I'm returning user.username before probably this username has loaded.
[2:18] The solution here may be to actually check that this user exists at all. Maybe I'll just say, "If there's no user, return a blank string." Or something like that. You could return loading, or you could return user loading or something like that. If I refresh the page here, you could see it says, "Christian, hello. Christian hello again. Hello for the third time." These are all of my messages here for my user.
[2:43] Now, one glitch here is going to be that these are based on a local instance of our user object. We have these users set up, which we get from Supabase. We do this on this load. Whenever a new message comes in, it will look for any new users it needs to get and retrieve them from Supabase.
[3:01] If I come up here, and I change my username, I'll maybe give it something like ChristianF, and I update the username, it does update here, but it doesn't update for each of these messages. That's because I don't have anything set up for subscribing to user changes and updating my users object locally, anytime that there's a change. Let's add that now.
[3:23] Below our messages' subscription, I'm going to make another subscription. This one will be called setup users subscription. It'll be an async function, very similar to the messages1. Here, I'll say, "Await Supabase from user onUpdate," because we're going to look for updates to our user table. This will take a payload with a callback function.
[3:47] What I'm going to do here is update my users' object. I'm going to say, set users." I'm going to use the function version of the React useState hook. I'm going to say, set users with users. This will be a function where I'm going to look at what this payload coming in is and update the user's object accordingly, if there's any update.
[4:13] The easiest way to do this is to say, user=userspayload.new.id. New here is going to be an instance of a user. I'm going to look for this user inside of my user's table. If it's found, then I'm going to -- I'll leave a comment here -- update user else, I'm going to return the users that I already have.
[4:40] Effectively, what I'm doing here is saying, do I know about this user? If I do, I'm going to update it, else, I'm going to return the data that I already have. The reason for this is that as the messages get updated, if someone submits a new message, and it's a user that we don't know about, which would be this case, we don't know about this user, we're going to make a request for it anyway.
[5:01] We don't even actually care about this update. We won't do anything with it. Though, this can be a tricky edge case. You may want to refine this and add another subscription for insert and check for any new use that come in the system.
[5:13] Again, this isn't exactly a perfect rock-solid system for handling subscriptions, because there's a lot of edge cases. The way we're doing this here will get you probably 80, 90 percent of the way there, and you won't have to worry about all these complex interactions.
[5:27] For now, let's focus on if there is a user and we need to handle an update. What we need to do is return a user's object from here. The easiest way to do that is to again, lean on object assign and pass in a number of arguments into it.
[5:42] First, an empty object, which we'll use to apply all of our changes to and then users. Our existing users object will get applied into this. Then, as a third argument, we're going to pass in another object which we'll use to update our specific user.
[5:59] If you aren't familiar with object assign, I'm going to do my best to explain this way of writing this which can be a little complex to some people which is passing in a user ID. I'm going to again say, payload.new.id.
[6:13] This is effectively going to create a new object with a single key which is going to be this user ID. This will be the payload.new user object.
[6:25] This is the equivalent of going in and maybe cloning this user's object and then updating based on the specific ID, but using object assigned we can do it all in one line and just say, "First add this user's object but then also add in this specific instance of payload.new which is going to be our new user."
[6:47] Finally, with all of this interaction set up, so when an update comes to our user table on Supabase, we want to update our corresponding state that we're managing locally. We do need to also call "Subscribe" at the end which will actually set up the subscription. Then finally, we want to actually call this function itself.
[7:07] We'll say, "Await set up user's subscription." If we save that, we can come back to our UI and we'll just test that if I edit the user name here to something like Christian 123 and I press "update," you can see that they gets updated everywhere inside of the UI.
[7:28] Not only is it updating here which is our current user reference, it's also updating everywhere that this user which is in this case, my specific user is referenced inside of our user interface. If someone else was sending messages, say you are user two or user your three, we would also see those updates occur here as well.
[7:47] All of our user tables will stay up-to-date. Not just our specific user, but we'll have subscription set up for all of the users in our database, which again is another awesome instance of how powerful real-time data can be in our applications.