 Hello everyone. In today's video, I'll show you how you can add profile pictures to your React application using Firebase Auth as well as Firebase Storage in which we'll store our user's profile pictures. So I'm just going to do a quick demo here. I'm going to log in using this account and you'll be able to see we have a profile picture already there. So I can browse and I can upload a different profile picture. It's going to give us an alert that says uploaded file. You can hit OK and let's refresh this page and you can see that now we're going to have our updated profile picture. Alright, so I'm at the Firebase documentation site here and I'm looking at the user object and under properties you can see photo URL. So this specific property is what we're going to be using to store the link to the profile picture of the user which will be hosted elsewhere. So in this case, we're going to be hosting the profile pictures of the users in Firebase Storage. So that's something we're going to be looking later in the video. But basically, this is our current application that I've brought forward from the previous video and the code is exactly the same. I have not touched anything. And if you guys want to source code to my videos, it's always in the link in the description. It's going to be in the GitHub repository and you can change the branch according to what video you're watching. So the first thing we're going to code is of course the user interface where we can browse and upload files as well as that small profile picture icon at the site where we can display the profile picture. So I'm going to go over to our code and create a new component in our source directory called profile.js and let's export default function profile. So this is our functional component in React. Let's go back to app.js. What I'm going to do here is I'm going to include the profile component here at the end as well as we have to import that. So import profile from, whoops, that's not what I meant. It's dot slash profile. And then we have to return something here. Let's return high. Let's just return high for now. It's going to be a string. All right, so I'm going to do this. You can see that high is right there. Nice. Okay, so now we can start to write code inside of our profile component. First of all, I'm going to make a div to contain everything. Then let's do an input type of file. So this is where we're going to upload our file to on change is going to be handle change, which we will include above with the return statement here. Let's do function handle change. Let's leave it as an empty function for now. Then let's go look at how that looks like. Okay, that looks nice, but it's stuck to the sign up login and log out buttons there, which means I'm going to give the div a CSS class so that we can, you know, space things up a bit. Let's give it a class name called fields. And let me check the index dot CSS to see if we actually have something like that. Yes, we do, but this has to be changed to a class target. Let me move it to the bottom of the file. And then that means I have to go back to my app.js here. Let me uncomment all of that. I'm going to go look for the HTML here and change this from ID to become class name because we want to apply the CSS class to multiple elements. We don't want it to be just an ID. All right, so let's go back to Firefox and let's see how that looks like. Okay, so now you can see there's a spacing there. What else I'm going to do is I'm going to add a button here. So button, let's say upload and let's see how that looks. Okay, so now we have our upload button. So now if I browse, I can upload this picture. I can hit upload, but nothing's going to happen right now because there's no functionality inside of our upload button. So we have to do on click equals to handle click. Then we're going to do another function here that says handle click. All right. Okay. All right. And then let's add a final element to display the profile picture of the user. So right now we have our browse. We have upload button. We need like a circle thingy where we can show the image. So I'm going to do image and then it's going to be a self closing tag. So let's call alt equals to avatar. Let's do class name equals to avatar. So I'm doing this class name because we're going to include some CSS to make this, you know, circle shape image. I'm going to go over to index.css. Let me copy and paste some code over. So I'm going to copy that and paste avatar. So these are just the styles, you know, vertical align with height, the border radius, whatever. We're going to include that here. And we have to give this image a source because right now there's no source to this image. You can give it a random source. I'm going to go and look for a avatar default avatar picture. So let's do profile avatar. Let's look for that. And I'm really liking this as the default profile picture. So I'm just going to copy image link. Let's go back to our code and then type that in. Let's refresh and let's see. All right. So now we have our default profile picture. What I'm going to do next is write some code to conditionally render this component. So I only want to render this component when we're logged in because if you try to browse and upload your picture when you're logged out, then where is that picture supposed to go? Right? So I'm going to go to add.js here, add some curly braces to wrap this profile component. I'm going to say if current user is not null, only then you'll render the profile component, which means if I log out, you can see that the profile component disappears. And if I log in, then that component reappears. And since we are on the topic of conditionally rendering components, I'm also going to add some conditionals to render the sign up and logging buttons only when we're logged out. So I don't want to see these buttons here when we're logged in. So I'm going to just add some curly braces here that says if current user is null, then only are we going to render these components. And we're going to wrap that in a React fragment because we're going to have multiple components and we can only have a single parent component. So oops, I'm going to just move that down, fix the indentation a bit. Let's move these all the way inside and indent those. All right. So now if I reload, you can see that the sign in and login buttons are gone because we're already logged in. All right. And since we're doing conditionally rendering like that, we no longer need these conditionals inside of the disabled field. And then let's also render the log out button because if I log out right now, you can see that sign up and login button reappears, but the log out button is still there. So we don't want to log out button when we're logged out. So I'll take this button here and I'll move it under inside of this conditional here. So I'm going to add a React fragment and let's put the log out button there and that's refresh. And you can see log out button goes away. You can sign in again like this. And then the log out button reappears and the sign in and login button disappears. So I'm going to fix the indentation a bit so it's easier to read. So right now the profile picture that we're getting here is actually coming from a hard coded value. So if I go over to VS Code in the image element, you can see the source is actually hard coded in. And this is obviously not what we want because in the documentation side, which I showed you earlier, you can see that the photo URL property is where we're actually fetching our photo from. So the thing I'm going to do here is I'm going to get the current user. I'm going to do the current user dot photo URL. This is where we're getting our photo URL from instead of just hard coding the value like this. So how do I get the current user object? Now this is something actually from the previous video in Firebase.js. We actually wrote our custom hook called useAuth which will return a current user object. So let's get the current user object like this. Current user equals to useAuth. I'm going to get rid of this here. And then of course we have to import useAuth from Firebase. So I'm going to do just that. With that, I can now do current user dot photo URL. And this is how we're going to get our image link. The thing is every time you're fetching data from an API in React, we always want to do that inside of use effect, which means I'm going to import use effect because we want to control the amount of times you're actually fetching the data from the API itself. Just going to do a quick use effect here. Give it an arrow function and give it some square brackets. Let's get rid of that and indent this. I'm just going to do something like set photo URL and put the current user dot photo URL here. And set photo URL is not defined yet because we are going to have to code that ourselves using state variables here. So const photo URL as well as set photo URL equals to use state. And there's going to be a default value here, which I know just what to put. We're going to put this placeholder avatar image here as the default of this state variable. So every time current user updates, we're going to rerun this code, which means I'm going to have to put current user inside of these square brackets. And let's take the photo URL state variable and just chuck it in the source of this image element here. And I'm going to go back to Firefox and refresh. And we're going to get current user is undefined. So the reason for this is because Firebase requires some amount of time for its initialization period. And during that time, current user object is actually undefined. So we have to check if current user is not null. Only then we're going to set the photo URL like that. Let's refresh this. And we no longer get that issue, but you can see the avatar here is buggy because we want to get the default avatar picture. And it's not showing up right now. And the reason for that is because current user is not null, but current user dot photo URL is actually null. I can even console.log current user dot photo URL here. Let's refresh. You can see it's null. So we are setting null to this photo URL state variable. And we're overriding this default Wikimedia profile avatar placeholder image. And we don't want that. So one way to do that is we can check if current user is not null as well as if current user dot photo URL is not null. Then only going to override this default placeholder. So let's refresh this. And we should get our avatar default picture. And a more elegant way of doing this is we can of course get rid of this and we can just add a question mark photo URL. And this is basically just JavaScript magic. If current user is not null and photo URL is not null, then only we're going to run this because if you don't have the question mark here, this will throw in an error because current user is undefined and undefined doesn't have a property called photo URL. So let's add a question mark there and refresh. And now it works as expected. And so now we have our default picture there. All right. So it's time for the actual juice of the video now. We're going to look at how we can actually browse and upload our photos to our storage backend. So basically it's in the storage section of your Firebase console. You can see right now we have no files. That's about to change right now. So let's go to our code and visit an old friend called Firebase.js. Now this is where we'll be writing some of our Firebase authentication as well as storage functions. So I'm going to import a handle to get storage. Much like get auth, we're just writing get storage now. And let's do const storage equals to get storage. It's just like get auth. We're just getting a handle to the storage API. And now I'm going to make a new section for all the storage functions that we're going to have. All right. So in the storage section here, I'm going to write export function upload. So we're going to have an upload function that will upload all of our profile pictures. And this function is going to be asynchronous because we're dealing with API calls here. I'm going to take in a few arguments here. I'm going to take in the file binary as well as the current user and set loading. And set loading is here because uploading files are not instantaneous processes. It's going to take some time to upload the profile pictures. So we're going to want to have some sort of loading state. We also want to have current user because we have so many different users and each user can upload their own profile pictures. We need to identify which profile picture belongs to who and the file is actually the binary, the picture, the PNG or JPEG or whatever it is that we're uploading to the database. So here I'm first going to make a file reference just like firestore and authentication. We always need a reference whenever we are working with Firebase and I'm going to do ref. So this is how you make a reference to a file inside of a Firebase storage database. So I'm going to have to import ref from Firebase slash storage and ref is going to take in the storage handle as its first argument. It's also going to take in a file location. Now the file location can be anything, right? It can be image dot PNG. It can be profiles slash image dot PNG. It can be your pictures slash image of PNG. This is basically the location of the file that we are getting the reference of. And in this case, we're going to generate a unique file name for each individual user because everyone's going to upload their own profile pictures and they're going to have their own unique file name. So to get uniqueness, we can just use the current user object dot UID. So we're getting the unique ID for each individual user from its current user authentication object, which we're getting from the parameters here. Then we can also concatenate dot PNG to this. So right now we're just hard coding dot PNG. We can do dot JPEG and other images file extensions and do the security checkings in the next video. So now that we have our file reference, what we can do is use this function called upload bytes, which we're going to import all the way from Firebase slash storage like this. Okay, so the first thing we're going to pass in here is of course the file reference, which is just telling you upload bytes, what location, where should upload bytes, where should Firebase put the file. And then of course the next argument is the actual file binary itself, which we are also getting from the parameters. And because this is a promise, we're just going to await that and we can store the return value in a variable called snapshot. And so that's just basically all of the code that we need to upload files to Firebase. So we just use upload bytes, which is something that you import from Firebase slash storage and file reference is basically the reference of the file to tell Firebase the exact location in which to upload the file binary. And then in this case, we're just uploading it to the root directory and then we're giving it a unique name. Of course you can put subdirectors as well. You just need to do like images slash and then you can just do like something like that and you'll specify a different location. But in this case, we'll just do it in the root directory and the file itself is the binary that we're going to upload all the way to Firebase. Now because this is an uploading process, you can see that we use await inside of an asynchronous function because this is uploading files and uploading takes time. It's not instantaneous. So we can use set loading in which we're getting from the parameters as well. So we're going to set loading a true and set loading false afterwards once we're done. And what I'm going to do as well is just give an alert here so we can give the user feedback once their file is uploaded. So uploaded file and then let's save this. So now that we have our upload function, we can go to our profile.js here and we can import that. So let's import use auth as well as upload. And then here you can see that we have our input and our button here which is in Firefox. You can reload this and basically I'm going to wait for this to log in and you can see the browse buttons and the upload buttons. It does nothing right now because handle change and handle click are empty functions right now. So let's go ahead and change that. So handle change here is going to take in an event. So we just call that e.target.files. You can upload multiple files. So we're just getting the first file here. That's why we have index zero and e is going to come from this on change call from the input type of file. So what we can do is we can get the file binary inside the React state. So I'm just going to do const image or maybe photo and then set photo. So this is actually a photo binary itself. I'm going to put now as default. And then we can say if e.target.files is not now then in that case we're going to set photo to e.target.files zero. So now when we upload something we should be able to upload that into the React state and now that we have the photo inside the React state what we can do is we can go to handle click and call upload. So what do we want to do in upload? There are a few parameters or arguments that we have to fill up. So file, current user and set loading. So file will just be the photo binary which we're getting from the React state because we just put that using the handle change function here. And the next parameter is current user. So current user is just current user. We're getting that from this use auth hook here. And what else do we have? Set loading. All right. So we need a loading state. So let's just go and create that as well. So loading and set loading. Oops. Set loading. And the default is going to just be false. We don't want to start off setting loading to true. So set loading is false and then just give that here. And now everything should be done. Let's see. Oh yeah. Loading is right now it's not used. So we have to use that. Let's go to the button here and let's say disable equals to loading. So when we're uploading files, we want to disable this button because we don't want a user to spam the button when you're actually uploading the file itself, right? So let's go back to Firefox and let's reload this. And I'm going to go over to the Firebase console just to show you that right now there are no files in our storage section. I'm going to go back to my React app and I realize something. You see the upload button? It's not disabled even though we have no file selected. So if I hit upload right now, it's just going to upload an empty binary which we do not want happening. So we can also disable the button when photo is null. So null is a default value inside of our photo stage variable. So if photo is null, that means that we want to disable this so it should be if photo is null. Yeah. All right. So let's refresh this and you can see that the photo, the upload button should be grayed out when we don't have a file selected. So now if we upload this profile picture you can see that the upload button is no longer disabled. I can hit that upload button right now and it's going to say uploaded file. Let's go check the console, let's refresh that to make sure that our file is indeed uploaded and give it some time there. And you can see that we do have our file here uploaded and it's the exact same file that I uploaded so it's good news. But if I refresh this, you can see that the avatar is still the default picture. So that's something that we want to solve. So let's backtrack a little here. I'm going to go back to the code and let's look at the image element. You can see that the source of the image is coming from the photo URL react state variable which is stored here and we're updating the photo URL variable using this use effect. And this use effect updates a variable based on the current user's photo URL property which right now we are not setting. We're not modifying it at all. We're just uploading the file, yes, inside of our Firebase upload function. We're uploading the file but we're not updating the actual user authentication object. So what we can do is we can do update profile which is a function that we're going to import from Firebase authentication. So here we are importing update profile. The next thing we're going to do is pass in the user of the profile that we want to edit. So it's going to be current user as well as the object you can see here in my VS Code IntelliSense it tells us like what sorts of properties that we can update. So I can just give it a photo URL and you can give it a new photo URL. In this case, I'm just going to paste a new photo that I found online. You can just save this. Let's go ahead and test that inside of our browser. Whoops, what is that? Okay, let's go to Firefox and reload this. Let's just put any file and let's just hit upload and it should upload and change to a different profile picture. And yeah, we get our different profile picture. I'm just going to show you the link that I copied and pasted. So it looks like this and indeed this is the actual image that we see here inside of our React application. So now the thing is we don't want to just hard-code this photo URL and just paste a random picture here. We want to actually upload the actual profile picture URL that we have just uploaded to Firebase Storage from here. So how we can get the photos URL is to use this method another method called getDownloadURL which is another thing that you're going to import from Firebase less storage. So yeah, I know we are importing a lot of things from Firebase but that's just the way this works. So the first thing we're going to put in here is the file reference of the file that we want to get the download URL of and then let's do const photoURL equals to this and then let's put the photo URL here like that. PhotoURL but the thing is you can see that the name of the key and the element has the same values so I can just write it once based on ES6 syntax. So now that that's done I can come back here to my Firefox and reload this and let's try to upload a different file here. Let's upload and it should say uploaded file. Let's refresh the page to see the changes and the profile picture is not changing so I think we did something wrong here and it's just me okay I forgot to put await here so we have to await this get download URL because this is an API call as well so let's save that don't forget the await guys let's reload this and see what happens and let's try to browse and try to upload this profile picture and it should say uploaded file let's refresh the page to see the changes and fingers crossed it will work. Yes it does work so that's what I was lacking remember to put the await there and with that I think we're done with everything so I can log out now and I can go to I can just sign up with different email so let's say hello world at gmail.com let's say some password let's hit sign up and then we're going to log in as hello world we have our default picture there so all good I'm going to upload this different profile picture it's let's hit upload and says uploaded file refresh the page and we should get to see the different profile picture and we do and that's it for this video leave your burning questions down in the comment section and I'll do my best to help you out or if you have any video ideas at all for me I do keep a list of all video ideas that I receive from my comments but until then see ya