Drag and dropping files in React using react-dropzone

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to look at drag and drop file uploads in react where you can create this Drop Zone area for the users to drop their files we're going to show them a preview of the files I've selected they're able to delete anyone they don't like we can also Implement some restrictions on the type or size of the files they can upload and reject the ones that don't meet our criteria later on we're going to also look at uploading these images to a cloud storage service like cloudinary hey friends welcome back to the channel if you're new here my name is Hamed I'm a full stack JavaScript developer and here on this channel we mainly talk about modern web dev topics like react and xjs so let's go to get started I have created a brand new nexjs app by running npxcreate next app I've also included a link to the source code in the description so if you want to follow along with me and all I had done so far was to replace the content of the home page with this simple component with this title tag and a custom Drop Zone component which we're going to build together now to implement the functionality for the file upload we're going to use a library called react Drop Zone and all this library is doing is that it exposes this use Drop Zone hook uh that we can call inside of our component to get some functions back that helps us create this div or container for our input file picker and the drag and drop functionality so let's just copy this code over and I'm going to explain what we're doing over here so uh first off you have to install this Library I have already done it so go ahead and install that library and we're going to get this use Drop Zone Hook from the library now we have to call this hook with some options mainly the on drop callback function this is a callback which is going to get executed once actually a user drops some files as you can see up top here we are defining this on drop with use callback from react so that we are not recreating this function over and over again every time this component re-renders and this callback function receives the accepted files it also receives the rejected files we're going to talk about later once we talk about other options that we can pass to use Drop Zone and this Hook is going to give back two functions mainly to to us the get root props and the get input props we're going to use those two functions and spread the properties returned from them on this outermost div and our input which then gives us uh the event listeners for click for drag events on these Dom nodes which is necessary for the drag and drop functionality or allowing users to click on or drop zone to upload some files now this form is not necessary I've just included here because later on we're going to use cloud energy to upload our files but mainly this div which is the outermost div with this get root props and this input file where you have this get input props now if I save this and go back to our um localhost you can see this drag and drop over here showing up now unfortunately when I click on it it opens but you won't be able to see like my browser window here because it's not part of the screen recording but it opens up so if I for example drop a file here you can see the text changes there and the reason why the text changes there is that we're listening or checking this is drag active property returned from this used drop hook which tells us if the drag is active with actually when the user is dragging something over our div and even if and if I open up the console here we're logging the accepted file so if I drag a file over here um we can see down here that we have this file array which is returned from Drop Zone hook that contains one file that gives us the name the path and the size and the type of the file that the user actually dropped over here now first thing that we want to do is to show a preview of the file the user just selected so they know something happened or it went through but before we get there on the home page you can see on this custom Drop Zone component that I have I'm passing in some classes to kind of design this Drop Zone but right now we're not using those classes over here so all I want to do is to design or to style this div and I'm passing in class name to my component so let me just go ahead and destructure class name in my component and I want to use this on my div so you would think to just pass it like so and that works for class name and as you can see now the design over here changed but the proper way of actually doing it is not to pass any other attributes to to this divs where you are spreading these two functions instead any attribute that you want to pass instead of passing it directly to that div you have to pass it to this function so pass an object and on that object you can pass in any attribute you would have otherwise passed in to the div and as you can see it didn't change anything but this way we're preventing ourselves from overriding the attributes set by this function or this function overwriting or or attributes so this is the recommended way from the documentation okay so what we want to do is to show the user a preview of the files I've actually selected so they know it went through so let's create a State here for files and set files with user State Hook from react and we're going to initialize this to an empty array let me just copy the code over here so inside of this on drop callback function instead of logging the files what we are going to do is that we are going to check to see if there is any accepted files and if there is any we're going to set them to our local state and the way that we are doing it here is that we're going to get any previous files that we have because we don't want to overwrite the files we want to enable the users to upload multiple files so we're going to get the previous file so we're passing in a function to set files uh our state setter that receives the current or the previous files we're going to spread all of those files and we're going to this newly received accepted files we're going to map over every file and for every file what we're doing is we're basically spreading over the content of the file with the object.assign it just copies the properties of this object into this object and returns so that's what objected assign does it's similar to doing this file and then this preview so it's similar to spreading it nevertheless so what we're doing is we're copying the file and we're just adding this preview property to it which is calling the create object URL on the URL interface by passing this file to it okay so every file now in our local state is going to have whatever that we were returning from the use Drop Zone hook here and we're just going to add a preview parameter or property to it where we can just show it with an image tag on our component over here so let me just save this so let's actually come down here and create a little preview section where let's render an unordered list where we get our local state we map over our files and for each file we're going to return a list element and let's just for now get the file that name let me just also pass in a key so it just stops screaming at us so file name over here let me just save this up and clear the console so if I drag a file over here now we are seeing this turbo.jpg which is the name of the file I just uploaded now we can go ahead and actually show an image over here so let's get image from next image and what we're going to do is we're going to set the source property of our image to the file.preview that we just created let's also give it an ALT tag for now uh with a width of maybe a hundred and a height of also a hundred this should show our image over here so we just yep you can see the image that I just uploaded there if I actually go ahead and upload another image we should be able to see that image as well because what we're doing is instead of replacing our state every time the user drops a new file we are just spreading over or we're receiving the previous files and we're just adding to that array let me just copy over a little styled component that I've created before so you don't have to watch me kind of write CSS over here as you can see on this component I'm using um hero icons from The Headless UI or the tailing team let me just import this up top over here and I'm going to explain what we are doing here so in this accepted files all we're doing is we're having a title we're still mapping over our files showing the image something from the documentation you need to keep in mind is once you have loaded the image in this image component it's better to revoke that object URL so it would prevent memory leaks if you are uploading or the user is uploading some too many images we're going to also use use effect later on to revoke all the URLs once this component is unmounted later on but for now this is the same image component that we had I'm also including a button so that the user can actually remove this specific file with that file name okay so let's just create this function over here where we would say const remove file it's going to receive a name and all it's going to do is going to set the files to get the files and actually filters any file whose file dot name does not equal this name we passed sorry if that makes sense okay so right now as you can see here if I go ahead and drag a file we see the preview over here we see the name down there and we have this little X icon that allows the user to click and remove this file and if I you know upload a couple of files over here you can see we see all the preview for them you can remove anyone that you don't want so forth and so on so that's the accepted files now the next concept that we want to talk about is the other properties you can actually set to this use Drop Zone where you can set some restrictions so for example if you want to accept only a specific file type for example we only want to accept image PNG or text HTML that's how you actually do it if you want to only accept let's say images any type of images so on this Drop Zone hook that I have over here I can have this accept property and this is going to be an object that I can pass in I can say image for slash star this indicates that we are accepting any kind of an image and in this case when you actually open up this file Peak here it only shows you the images unfortunately you don't see my file picker here um but this means that if the user now tries to drop something else other than an image it's not going to get accepted it's going to go in the rejected files now to see the rejected files that actually don't pass this restrictions that we pass to use drop zone I'm going to use a size restriction so let's go back to here on this Drop Zone component you can see all the different props or values you can pass in so you can pass in maximum number of files or Max size so I'm going to copy this and say hey we want to accept images and our Max size for each oh sorry our Max size for each file let's say it's 124 and that's number of bytes so times a thousand that's let's go back here and if I refresh if I now drop a big file that I have over here I just dropped it or let me do this actually Let me refresh I'm going to drop the same four files that I dropped before and out of them only three are inside the accepted files and one which is bigger than a Meg megabyte it's actually not included in our accepted files now to show them also here this on drop callback function as I mentioned on top of the accepted files it also receives the rejected files so let me just get that here rejected files and maybe for now we can just log the rejected files so let me just refresh over here and I'm going to drag the same four files again so we are dealing with the same thing as you can see down here in this array in the console I have my rejected files it's an array of objects each object has an error property and the file property so it tells you hey this while you were trying to upload with the turbo jpg that's a big image what you can see the size is you know five megabytes it's more than one megabyte that we have set it's an image so it allows the image but the size restriction is not passing through and it gives you an error object too so the errors is an array actually of error kind of messages or objects where a file may have multiple errors so if I let's say try to drag and drop a large PDF uh where it's PDF it's not image so that's one error and it's large more than one megabit and that's the second error that we're going to get so on the air we have that the file is too large and the message is that what you can show to the user okay so let's also keep track of our rejected files so right now we have a local state for our files let's create another state from our use state so this time let's initialize it to an empty array and let's call these guys rejected files and or let's just say reject it and set rejected okay and what we're going to do down here instead of lodging this rejected files that we received from this on drop function we're going to actually do the same thing with it here to set our local state so we just copy the code that I have over here so all we're doing this time is again if there is any rejected files we're going to get our previously rejected files and we're going to just append this files to those files now for the rejected files we're not going to create a preview because they've been rejected we just want to show the maybe file name and the reason the error message that we are rejecting those files so we have this state we have this state Setter let me just also copy this section that I have here for our rejected files so we can actually show them on the page so let me copy over this rejected section and again with this we have this rejected file section and we have to create this remove rejected as well which is a similar function to the remove file function we created that receives a name and this time it calls this set rejected and actually gets the files these are the current files and it's going to filter um now remember that this files here in our state actually it's like a wrapper that has the error property and the file property so you have to destructure the file out of it so file is structured out of it where the file name is not equal to name okay so that's our remove files now if I upload the same four Images again you can see over here that three of them pass and are accepted this one which is bigger we have the file name as well as the error message that says I hope you can see this file is larger than this million bytes or one megabyte so therefore it's being rejected now we can also go ahead and remove that file it's the same functionality that we had up there now similar to the accepted files up there I'm just getting the rejected files over here mapping over every item and remember there's a wrapper around the file because it also gives us the error so it's an object with the file property and errors so I'm just structuring the file and errors from it for every file I'm showing the name I'm also mapping over the years remember the errors was an array of different error objects with code and message so we're getting the errors array if you're mapping over each one and we're showing the code we're showing the message and we're setting the code as a key now I've also included this button that removes that specific file from our rejected files in The Next Step let's actually look into uploading these images to our cloud storage system up until this point we've been handling these files locally in the browser we've been using the file reader API or the react Drop Zone component to just allow the the user to select these files we haven't uploaded any image to the cloud or to our database for the purpose of a cloud storage I'm using cloudinery you can use S3 or Google Cloud Storage the steps and the concept would be the same they either going to give you an SDK you can use to upload images or in the case of cloudinary wicket set and upload preset which exposes a rest API endpoint for us to easily upload images so if you come to the settings tab under the upload section if you scroll down you can see these upload presets that you could set all you need to do is to hit this add upload preset where you can set a name and you can specify a folder where these images would be saved in your media library and for the signing mode you're going to select unsigned and I'm going to select the unsign for the purpose of this tutorial the signed version is where you need to authenticate for the API to work but the onsigned version just works out of the box and under this upload manipulation you can also set some parameters so incoming transformation you can transform the images as they're coming in to a specific size quality so that if somebody's for example uploading a big image you can just reduce it to a smaller size image so it's not going to fill up your storage size the only other thing you need from cloud energy is your API endpoint so if you come to your dashboard you can see this API environment variables if you click on this more info button you can copy your own specific API endpoint and maybe bring it back to your project and set it as a local environment variable so that you could hit this endpoint this is a rest API endpoint where it allows you to upload your images I'm prefixing this Cloud inner URL environment variable name with next public so it exposes it in the client side because if you're sending this from the client side without it it's going to be only accessible on the server side which is not the way that we're doing it here so we just go back bear with me for a second I'll just copy over the code that I'm going to explain to you what exactly we're doing here here so as you can see this upload to cloudinary button all it does is that it submits this form we had from the beginning I have added this handle submit function and this is the logic of uploading our files to clattering so let's see how we're doing this so uh first things we are preventing the default behavior of the form submission in the browser we're looking to see if we have any files over here and if we do we're going to create a new form data object we're going to looping over mapping over our files State and for each file we're going to append a new entry to our form data with the content of that actual file and the only other thing we need to do which is cloud interior specific is that we have to append this upload preset key into our form data that's set to the namespace of our upload preset that we just created together so whatever name you had there you will put your name over here mine is called friends book so I set upload preset to friends book and because it's an unsigned upload uh kind of endpoint you don't need to authenticate as long as you include the name of your opposite over here I'm getting the URL from the local environment variables that again V set together and as I explained before it's a prefix with next public so it's exposed to the client side because we're running this in the browser and we're sending a fetch request to that endpoint which is our cloudinary API endpoint and method.post and the body is just that form data we created here with the files inside of it so if you're not going to Json a stringify or body it's just the form data if you're going to get the response back turn it into a Json and log this data in our console so let me just go ahead and take in a file over here drag it there and hit upload and we're going to get our response back from cloud native let me just drag this a bit bigger so on the cloud enter you say you can see that it gives you back the information of the file and it also gives you this secure URL which is the URL that you can securely access there's a specific image we just uploaded uh to our cloudinary we can then use this as a string maybe to save a record to our database instead of having the files in our database we're going to upload it in any cloud storage that we're using and then getting that string getting that URL back and then saving that URL into our backend database whether it's a profile image or maybe they're trying to submit a post like in Facebook and Twitter you can just save this URL back in your database that's a wrap for this video folks we looked at drag and drop file uploads in react using react Drop Zone uh we saw how we can use native browser apis to show the user a preview of the selected files without hitting our cloud storage or database we also looked at how we can restrict the file selections by size or by type and reject the files if they don't meet the criteria we also looked at how we can upload the selected images or the accepted files to our cloud in your service or any other cloud storage service for that matter get a URL back that we can maybe in the next step save in our database if you have any questions hit them in the comments for me I'll try to be as responsive as I can down there if you learned something from this video give it a like it helps put it in front of more people like you and I'll see you in the next one bye
Info
Channel: Hamed Bahram
Views: 15,996
Rating: undefined out of 5
Keywords:
Id: eGVC8UUqCBE
Channel Id: undefined
Length: 26min 26sec (1586 seconds)
Published: Sat Feb 11 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.