In this video, you're going to learn everything that you need to know about uploading files in your React applications. We're going to do this in a very simple way. We're not going to be using any third party library, and we're going to be following all of the best practices and design patterns in React.
Now, before we get to that, there's two things that I want to quickly mention. The first one is that if you enjoy the way that I teach in my videos, and you're also serious about learning React, you should totally check out my course, Project React, which goes way more in depth than anything that I can teach in any of my YouTube videos. It will take you and teach you everything that you have to know to become a great React developer, and it's going to walk you every step of the way.
If you're interested, I highly recommend it. It's called Project React, and it's going to be linked in the description. And the second thing is that I also have a newsletter that's all about React.
It's called Import React. I love the name. It's really cool.
It's really clever. And it's all about React. You get tips, tricks, and really cool articles delivered to your inbox completely for free every single week.
If you're interested in that, it's also going to be linked in the description. Now we can begin the video. Alright, so let's begin.
So let's start implementing file uploading in a React application. So what we have here is a very simple application that we're going to be working with, we just have this one app component, right, it currently does nothing. And we're going to have to implement file uploading functionality inside of this component.
Now, what I always like to do first, and generally, this is just a best practice in React, is anytime they're doing some sort of new functionality, you want to put it in a new component. So that's what we're going to do, we're going to come here and we're going to go inside of SRC, we're going to create a new folder to keep ourselves organized. And we're going to do components like this.
Inside of components, we're going to create a component that we're going to call the file uploader. So we're going to do file uploader, like this dot TSX. In here, we're going to put all of the functionality that is related to uploading files inside of our application.
So first, we're going to do export default function, file uploader. And I believe I have a typo uploader. There we go.
And in here, we're going to return some JSX. For now, we're just going to leave this empty, right, because we're going to start building this in just a moment. Then once we have this, we can now go back here to the app component.
And we can get rid of this causal solutions over here. And we can directly import and use our file uploader component from the components folder like this. And let me just get it right what happened there we go.
Now we have a file uploader, it's currently empty, but at least we have it in a separate component, which we can now use in here in this app component, or any other component that we want to now implement and have file uploading functionality. Now the first thing that I want to do inside of here is just create and put a diff in here instead of just an empty fragment like this. And because we just want to put here our input, and we're going to do here type and that is going to be file like this.
And we're just going to put this input over here, just so that we actually have something that we can actually show. If we open up the application over here, we have a simple input, we can click it, we can select the file, but obviously selecting a file does nothing because we haven't really configured any other logic besides just the default behavior to actually show the file as part of the input, right. So that's the next step for us.
So the first thing that we actually want to do is we actually want to show some details about the file here. And we want to do that because essentially what we're trying to do is we're trying to get access to this file inside of our component here as state, we want to take the file that we receive here from the input, put it in state in our component, so that then we can use it for one to actually show the details of the file in the actual UI. So in here, and for two, we can then use that state use that file that is in the state to actually upload it in a function that we're going to send it to some back end, right.
So that's the first step is to create state to hold the file that we get from this input. So for that, we're just going to come here and we're going to make a state variable. So we're going to do const.
And we're going to do here file set file. And we're going to use use state import this from react. And here, we're just going to put no for now.
Now because we are working in TypeScript, we are going to add some types over here to the state. But if you're not working in TypeScript, it's totally fine, just ignore this part, it doesn't really affect the actual core of the video. But I'm going to come here and I'm going to pass you the type as file or no.
So this state variable is either going to be a file, and this is the default TypeScript file, class file type, whatever, which contains all the details of an actual file. Or it can actually be null in the case where we don't have a file, which is also going to be the initial state of this state variable. And then the next step for us to do is to take the file from the input and actually put it in a state.
And to do that, we're going to have to access the on change event handler of this input. So I'm going to come here and actually create a new function, we're going to call this one function, handle file change. And this is going to take an event over here.
So we're going to do event, I'm just going to put it as E. And this is going to be a change event, which we're going to import directly from react. And here, we're going to pass HTML input element to signify that this is the change event of our actual HTML input element.
And directly this file, we cannot actually pass it here on change. And we can pass handle file change. And there we go, we have no errors, because the event that we have here is the actual event that matches that is getting passed from this on change event handler.
Now inside of the function, what we want to do is this is going to contain this event over here is actually going to contain the file that we actually selected in this input. So we're going to want to check for that file. And if it is there, we're going to want to get it and set it in the state.
So we're going to do if E dot target dot files, this is going to be all of the files that are currently in the input, we're going to do set file, and we're going to pass your E dot target dot files. And we're going to pass the first file, we're only going to keep it things keep things simple over here and just have a single file input. So we're going to hard code manually to get to the first file in this E dot target dot files and put that put that directly in the state.
So now with this, what we've done is essentially whenever this input on change gets called, which is going to get called when we actually select the file on the input in our browser, this is going to call this function, we're going to check here if E dot target dot files is there. And if it is, we're going to access the first file and set it in a state. And then after that, we can now use this file because now it's part of a state of this component.
And we can actually display the details inside of our component inside of our JSX. So what I'm going to do is I'm just going to take care of some markup just to make things a little bit simpler to not risk copying something and making a mistake. I'm just going to paste your some markup to basically say that if we have a file over here, we're going to render this diff where it's going to have some styles, margin, bottom text SM.
And it's going to have here the file name, which is going to be file dot name, these are all properties that are available on the file object. And we're also going to do file size and then to fixed to get the actual kilobytes of the file. And also the file type, is it an image, is it a document, whatever type the file is, is going to be shown in here in our actual component.
And I also want to just come here and add maybe a space y class, we're going to do class name, and we're going to do space and then y. And then let's make it maybe four, just to have some space between the actual input and the file to kind of keep things a little bit more, I guess, visually pleasing. So now if we go back here, actually, let's make it two, because I just saw it for like a quick second, let's make it two.
If I come here, I will now select the file that is going to trigger the on change event handler of the input. And when it does, that file is going to go in the state and then we're going to have a file in the state, which means that our JSX parts that has the file details is going to get shown. And as you can see here, that's the name of the file, that's the size of the file in kilobytes.
And that's the type of the file, it is an image and is specifically a JPEG image. So this is great. This works exactly as we expect.
Now before we continue, I just want to take a quick moment to really think about what it is that we're actually doing in this video. Because what we're doing here is we're following an approach that is called learning by doing, right, you're not just watching a boring lecture video that's all about theory, you're actually watching me do it and implement file uploading in React, which is learning by doing, which is great, because that's exactly what brilliant, the sponsor of today's video is also doing. So brilliant is a place where you learn by doing you have 1000s of interactive lessons in various topics such as math, data analysis, AI, and of course, more importantly, for us programming, brilliant has a learning platform that is designed to be uniquely effective.
Their first principles approach helps you build understanding from the ground up. Each lesson that you have on there is filled with hands on problem solving that actually lets you play with concepts, which is a method that has been proven to be six times more effective than watching traditional lecture videos. Plus, all of the content on brilliant is crafted by an award winning team of researchers, teachers and professionals from places such as MIT, Caltech, Microsoft, Google, and more.
And brilliant helps you build your critical thinking skills through problem solving instead of memorizing. So while you're building real knowledge on specific topics, you're also learning how to become a better thinker. And they have so many great courses on there, it's really hard to choose.
But if I had to recommend one and pick one, I would pick thinking in code, which kind of follows what we're doing in this video and teaches you solid foundations for computer science that are going to directly help you as a react developer. To try everything that brilliant has to offer for free for a full 30 days, visit brilliant. org slash causes solutions, scan the QR code on the screen, or simply click the first thing in the description.
You're also going to get 20% off an annual premium subscription. Thank you once again to brilliant for sponsoring this video. And now let's continue learning about file uploading in react.
Great. So now that we have this done, we can actually move on to the next part of this, which is actually handling the uploading of the file. And for that, I'm going to come here at the top and I'm going to define a new type.
So we're going to do type upload status. And that is going to be either we're going to start it at idle, which is going to mean that it's nothing happening, it's ready for it to do something to upload, or it's going to be uploading, or it's going to be success, which means that the upload has been executed successfully, and there was no error. Otherwise, if there is an error, it's going to be error like this.
And this is going to be our upload status. Now generally, you want to do this in actually have one state that represents all the possible ways that your state can be in, instead of having separate states like howThis is a video by Darius Cosden, from the company called Cosden Solutions, from the is going to be equal to use state and we're going to pass it here upload status as the type and we're going to start it at idle because that is going to be our initial state. Then we're going to come here in the actual JSX and below the file over here, what we're going to do is we're actually going to render a button that we're going to be able to click that is going to trigger the file upload.
So we're just going to make a check here first that we have a file, because we only want to actually allow a file to be uploaded if we have a file in the state. So that's our first check. So we're going to do file.
And then we're going to do end, end. And then we're also going to check that the status is not equal to uploading, right? Because we don't want to render this button, if we're already in the process of uploading something.
So if those if both of those conditions are true, then we're going to come here and we're going to render, let me just see how I actually did it, we're going to render here a simple button, where is it, we're going to render a simple button over here, that is going to be button. And here, we're just going to put upload like this, right? Right now, there's no function attached to it, we're going to do that as the next step.
But for now, we just have a button. So let's see how this looks like in our actual application. So I'm going to come here and actually choose another file to upload.
And you're going to see that as soon as we have a file, we still have the same details. But now we have this upload button, which currently does nothing. But we're now going to be able to use it to actually upload the file, this button is only visible if there is a file.
And if the upload status is not currently uploading, which is why we're seeing it currently on the screen. So that's great. Again, this works exactly as we saw.
Now let's come here and actually create a function that is going to handle our uploading. So we're going to come here and make a new function. And we're going to call this one function handle file upload.
This is pretty simple, pretty self explanatory. In here, the first thing that we're going to want to do is again, we're going to want to make a check if we have a file, if we don't have a file, we want to return early and just not execute the rest of the function. So we're going to do if we don't have a file, then we're just going to return early and again, not execute the rest of the function, then what we're going to want to do is update our status over here to set it to uploading, because now we're going to be starting the actual uploading process.
So we're going to do set status, and we're going to put your uploading over here to signify that we're now starting the actual uploading status. And the benefit of us having just one state variable called status over here, instead of having many is that we just have to make one state update over here. And it's going to update our entire component to set it to uploading.
And we're never going to have the risk of any possible states or managing multiple states and risk them not being always in sync, then what we're going to do is we're actually going to take this file, and we're going to convert it to form data, because that is what we're going to be using to actually send it to a back end. So we're going to do const form data equals new form data, we're going to instantiate a new form data class. And here we're going to do form data dot append.
And we're going to do here file, and I'm going to pass your our file like this to our form data. So now we have this form data object, we can send this as a POST request. And this is going to contain our file, which is going to get uploaded to our back end.
And then we're going to come here and we're going to change this function actually to be an asynchronous function because we are going to a sync, there we go, I always miss up when I write a sync, because we are going to be sending a request to a back end, which is asynchronous in nature. And then we're going to do try, and we're going to put here this, then we're going to do our catch block like this. And we're going to catch an error if there's an error.
So first, what we're going to do is we're going to await a fetch request. Now we are going to be using axios for this, just because the way that they handle file uploads, especially when it comes to upload progress is simpler. And generally, it's something that I would recommend they use in a project anyway.
So axios just makes a lot of sense here. So we're going to do axios. And we're going to import axios from axios dot POST.
And we're going to send here to a URL, let me just cat and copy the URL here to make sure that I don't make a mistake. This is essentially a free and open source kind of back end that you want that would actually simulate uploading something there. And we'll actually return to us a response that we can actually expect.
And we can use that to show in our actual UI, we don't have a real back end for this video. Because again, it doesn't really make sense to set all of that up, this one is pretty sufficient. And this one will act as a real back end because it really is it just simulates all of this, but it really is a big real back end.
And then as the second argument, we're going to pass form data, that's going to be our data that we pass to request. And then here, we also have to pass the content type. So let me just copy this correctly.
So again, I don't risk making any mistakes, we're going to have to pass the content type as a multi part form data, right to be able to send the actual form data to actual requests. And I believe I have a mistake, it's not like this, we have to pass it as the headers, like this headers is going to be an object. And here we're going to have the content type inside of the object.
There we go. So now we're passing form data to our post request. And we're passing actual form data in the actual request.
So everything should work as we expect. Then after that, after we awaited this request, if everything went correctly, we're going to now set the status to success. So we're going to do set status to success.
So we're going to do here success. Otherwise, if we have an error, we're going to set the status and we're going to put your error like this, we're not going to do anything with a specific error, we're not going to do anything with a specific status code or anything like that, we're just going to track the simple status is successful, is it not. And then based on that, we're going to show something in the UI.
And then I'm just going to come here in our JSX. And I'm going to copy some other markup to just handle and show something in either case, if we have success, or if we don't. So let me just make a little bit of space here to kind of orient ourselves a little bit.
So the only thing that I added is this two sections over here. So if status is equal to success, we render a paragraph with some styles, I believe we should not have any margin top here because we have the space y, right. So if we have an actual status of success, we just rendered this paragraph that says file uploaded successfully with a green color.
Same thing if we have an error, we just said upload failed, please try again, really simple, nothing really fancy here. So let's now go to the application and actually check out and see how this works. So I'm going to come here, select the file, and we're going to put any file.
And now when I press upload, it is going to take a little bit of time. And then we're going to actually see an upload our file to an actual database, right, it's not going to get actually saved. But we're going to get a return a response from the actual server that we're uploading to, which is either going to be success or error.
And we're going to be able to see that displayed here on the screen. So let's press upload, it's going to take a little bit of time. And then after it's been uploaded, well, it did not work.
So let's see the console. Do we have an error? No, we don't, I believe I know what my mistake is.
And yes, we have nothing attached to our button, I forgot about that. So on click, the button is going to handle file upload. And now we should be good to go.
Let's go back here. Let's refresh again, let's select our file again. And hopefully this time I'm going to press upload, the button disappears, and we have file upload successfully.
There we go. It works exactly as we expect. And also, I hope that you saw when I press upload, and the upload is happening for a split second, while the upload is happening, the button actually disappears, because that's exactly what we said, we said that this button should only be visible if the status is not currently uploading.
And if we have a file, while we have a file, and right now the status is not uploading, well, let me see what happened. Let me just go back to the status over here, we have a file, now the status is not uploading. Now it is.
And now it's not it's successful. So the button shows again. And then we also have this success message indicating to us that everything went exactly as we expect.
So there we go. This works. Now, this is great.
But we actually have one more step that we want to do. And we actually want to implement upload progress indicators. Because right now, the only thing that we're seeing is when an upload is successful, we're not actually seeing the progress as it being uploaded, it would be really nice as a user to have a percentage shown on the screen that indicates to us how much of the upload has actually happened, and how much of the upload is left to be uploaded.
So that's what we're now going to start implementing. So for this, we're going to want to create another state variable. So we're going to come here and do const.
And this one is going to be upload progress like this, this is going to be used to track the actual progress of our upload, then we're going to do set upload progress like this. And this is going to be equal to use state and we're going to put it here, we're not going to give it a type because it is going to get inferred, we're going to use zero as a type, this is going to be a number and we're going to increment this number and update it as we're actually handling the file upload and the file progress upload. Now the reason why we used Axios and I mentioned this a little bit earlier in the video is the fact that Axios makes it really, really simple to actually attach a listener and event handler on the upload progress and actually call even react state updates as the upload is happening.
And all of that happens in here in this object over here, this config over here, what we can do is besides headers, we can actually pass on upload progress. And you can see here, this is a function. And this one will give us here a progress event, which is going to be let's do here, progress event.
And that progress event is actually going to contain our actual values of how much of the upload has happened and how much of it is left to go. So in here, what we're going to do is we're going to do const progress, we're going to have to calculate the progress. And this one is going to be progress event dot total.
And this is going to be an optional because we may not have a total. So we have to put a question mark over here. And then if we have a progress event dot total, we're going to do something.
Otherwise, we're going to return zero like this, because if we don't have anything, we're just going to return zero as the actual upload progress. And then in this case, where we actually have progress event dot total,What we're going to do is we're going to do math dot round. And here we're going to pass progress, event dot loaded, which is going to be the actual part of the event, how much has been successfully uploaded, we're going to do that times 100.
And we are going to divide this by progress event dot the total, right. So we're taking I have here a mistake, it's run like this, we're taking here essentially the amount of the progress that has been uploaded so far times 100. And we're going to divide this by the total amount that is to be uploaded, this is going to give us an actual percentage that we're going to have here in this progress variable.
And then once we have this progress variable, the beautiful thing about using Axios for this is we can directly call set upload progress, and we can pass your progress directly and it is going to get called and update our state every single time. So essentially, what's happening here is this is a function that comes directly from Axios, and it gives us access to the progress event, which has the amount of upload that has been finished and the amount of upload that is left to go. And then based on this function, we can actually call state updates inside of a react state component.
And it's going to automatically update as we're getting updates from Axios in the file upload. So as we're uploading the file, it is going to get and set the upload state in the state of our component here. And we're going to be able to use this and show it in the JSX to show it to the user of how the upload is currently doing, which is great.
Now, we're also going to want to come here where we're setting the status to success, we also want to just make sure that if we have success status, we also have an upload progress of 100. It just makes sense to have it that way, in case this function doesn't really hit that 100 directly, which sometimes it might not. So we're going to do set upload status and here upload progress, sorry, we're going to put this as 100.
Right. And then in the case of an error, we're going to do the same thing. But we're going to do set upload progress.
And we're going to put here zero, we're doing this because in the case of the error, this is not going to reset the upload progress to zero, we have to manually do it here inside of our function. And then we also have to come back here at the top of the function and also added here because whenever we're going to trigger a file upload a new file upload, we want to make sure that whatever progress was there before, if there was another file that was uploaded before, we also want to make sure that we reset the upload progress when we're uploading something fresh. So we're going to do set upload progress.
And we're also going to put this here to zero to reset the upload progress. And then the last step for us to do is to come in here to our JSX. And what I'm going to do is once again, if you don't mind, I'm going to take care of some markup, which is just going to render a progress bar type of thing, a progress indicator.
So this is the markup over here. So if status is equal to uploading, then we have this div over here, it has some styles, and then we're passing here the width of the div as the upload progress in a percentage. And that's it.
And then we're displaying here the actual percentage uploaded. That's really it. It's just some JSX that just uses the upload progress and displays it on the screen.
So let's now go and look at how this actually looks and behaves. So we're here, we're going to select a file again, I'm going to select the same logo. And now we're going to upload this and we're going to see we have a progress bar and it showed uploaded.
And once the upload was done, we have file uploaded successfully and everything works, I can press upload again, and it's going to trigger another upload. Once again, I press it again, it triggers an upload. And we're always seeing from zero to 100.
Let me now open up my console over here. And let me just go here to my network tab and actually throttle everything so that hopefully we can see it a little bit slower. If I now press upload, you see that as we're getting uploads, it's actually happening.
And now as the upload is getting finished, we now have success. And there we go, we have the button. Once again, for good measure, we're going to press upload, we see the progress every time that it's incrementing our state update is happening, we're seeing it on the screen.
And when it's done, everything is uploading and the states are updating exactly as we expect. This works. And in terms of functionality, well, this is pretty much complete.
That's all that you really need to handle file uploading in a React application, you create a new component, you have a state for your file, you have a state for your status, you have a state for your progress, if you care about that, if you want to use that and show it to the user, then you have a function that will just set the state of the file and you attach it to the actual input on its own change event handler, then you have a function to actually handle the file upload, I would recommend they use Axios, but you could use anything that you want. And then you actually pass the file and then you hook into the actual events of the upload to get the actual upload progress and you put that in the state. And then of course, you handle your statics and your upload progress at every step of the way.
And then you just use all of your state variables, all the information that you already have in this component to just display them to the user. It's pretty simple, it's straightforward, but it's very efficient, and it works. So if you want to play around with this, which I highly recommend, you're going to be able to find the GitHub repository in the description, as is the case for pretty much all of my tutorial videos on the channel, play around with this, extend this if you want.
For example, here, we're only handling one file at a time, but you could easily extend this to handle multiple files, you would just have to make some slight changes to the way that you handle your uploads to basically go and loop through every single file and make a separate fetch request for every single file. We're not going to do it in this video, it's a little bit outside the scope, I wanted to keep things simple, but you could easily do it and you have the code now in the GitHub repository to be able to do it. So go ahead, I highly recommend it.
If you enjoyed this video, and you want to see more videos just like this one, make sure to leave this video a big thumbs up. You can also click here to subscribe, or you can click here to watch a different video of mine that YouTube seems to think that you're really going to enjoy. And with that being said, my name has been Darius Kozun, this is Kozun solutions.
Thank you so much for watching, and I'll see you in the next video. Ciao.