File Uploads in React (Complete Tutorial)

4.46k views5980 WordsCopy TextShare
Cosden Solutions
Try Brilliant Free for 30 days 20% Off Premium Membership → https://brilliant.org/CosdenSolutions ...
Video Transcript:
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.
Copyright © 2025. Made with ♥ in London by YTScribe.com