Creating a React Component That Allows Csv and Txt File Upload

While working on a React project, I implemented a responsive file upload component that supports drag and drib without using any libraries. Most of the file upload components online used libraries such as react-dropzone to back up drag and drop. So, I thought I'd share how I made the component and testify a typical apply example for it.

End result

Figure 1: File upload component used in a form (case use case)
Figure 2: Responsive file upload component

The features include:

  • elevate and drop without using any libraries
  • displaying epitome preview for paradigm files
  • displaying file size & name
  • removing files in the "To Upload" department
  • preventing user from uploading files bigger than a specified size
    • Note: this should likewise exist done on the backend for security reasons

Project Setup

Prerequisite: Node (for installing npm packages)

If you are familiar with building React applications, the easiest way to set up a new React projection is by using create-react-app. And then, run the following commands in a terminal/command-line:

            npx create-react-app react-file-upload cd react-file-upload                      

Enter fullscreen fashion Leave fullscreen mode

To ensure everything was ready properly after you run npm outset, the following should appear once you lot visit localhost:3000 in a browser:

Alt Text

Before building the component, allow'south change and remove some files to get rid of unnecessary lawmaking.

  • Modify App.js to the post-obit:
            import React from 'react';  function App() {   return (     <div></div>   ); }  export default App;                      

Enter fullscreen mode Exit fullscreen mode

  • Alter index.js to the following:
            import React from 'react'; import ReactDOM from 'react-dom'; import './alphabetize.css'; import App from './App';  ReactDOM.render(   <React.StrictMode>     <App />   </React.StrictMode>,   document.getElementById('root') );                      

Enter fullscreen way Exit fullscreen mode

Remove all files in the src folder except

  • App.js
  • alphabetize.js
  • index.css

File Upload Component

Installing Dependencies

The dependencies we will demand are:

styled-components

  • For styling the component
    • styled components allow for mode encapsulation and creating dynamic styles via props

node-sass

  • For compiling Sass styles used in styled components (Optional, can use CSS)

To install them, run npm i styled-components node-sass.

Folder Construction

A adept convention for structuring folders and files is to create a components folder that has a folder for each component. This makes it easier to find the logic and styles for each component.

Following this convention, create a components folder in the src folder and so a file-upload folder inside the components folder.

Lastly, within the file-upload folder, create 2 new files.

  • file-upload.component.jsx
  • file-upload.styles.js

Land

Since nosotros are creating a functional component and need to use state, we will use the useState claw.

The useState claw returns a stateful value which is the same as the value passed every bit the outset statement, and a role to update information technology.

For our purposes, we will demand state to continue track of the uploaded files. And so, in the file-upload.component.jsx file, add the post-obit:

            import React, { useState } from "react";  const FileUpload = () => {   const [files, setFiles] = useState({});    render (    <div></div>   ) }  export default FileUpload;                      

Enter fullscreen mode Leave fullscreen fashion

"Shouldn't we utilize an empty array instead of an empty object for the files state?"

Using an object volition allow usa to easily manipulate (add/remove) the files state and forestall files with the same proper noun from being uploaded more than in one case. Hither is an example of how the files state will look like:

            {  "file1.png": File,  "file2.png": File }                      

Enter fullscreen style Exit fullscreen mode

If we used an array it would crave more work. For instance, to remove a file we would have to iterate through each file until we find the one to remove.

Note: File is a JS object. More info tin can exist constitute at https://developer.mozilla.org/en-US/docs/Web/API/File.

useRef hook

If you expect at Figure 1 above, you volition notice the user can either drag and drop files or press the Upload Files button. By default, an file input tag will open the file explorer once it is clicked. Even so, we want to open it once the Upload Files push button is clicked and so we will crave a DOM reference to the file input tag.

To create a DOM reference, we will apply the useRef claw. The useRef hook returns a mutable ref object whose .current property refers to a DOM node (file input tag in this instance).

In one case we apply the useRef hook, we must laissez passer the returned value to the ref attribute of the file input tag, similar so:

            import React, { useState, useRef } from "react";  const FileUpload = (props) => {   const fileInputField = useRef(null);   const [files, setFiles] = useState({});    render (    <input type="file" ref={fileInputField} />   ) }  export default FileUpload;                      

Enter fullscreen fashion Go out fullscreen way

Props

The component will take the following props:

  • characterization
    • Determines the label of the component (e.grand. "Contour Image(s)" in Figure 1 above)
  • maxFileSizeInBytes
    • For preventing files above the specified size from being uploaded
  • updateFilesCb
    • A callback office used for sending the files country to the parent component

"Why do we need to transport the files land to the parent component?"

Typically, the file upload component will be used in a form and when working with forms in React, the component stores the form data in the state. Thus, for the parent component to also store the uploaded files, we demand the file upload component to send it.

"Why do we need use a callback function to send the files land to the parent component?"

Since React has unidirectional data menses, we cannot easily pass data from the child component (file upload component) to the parent component. Every bit a workaround, nosotros volition laissez passer a function declared in the parent component and the file upload component will telephone call that function with the files country every bit an argument. This process of sending information from the child to the parent can be further explained at https://medium.com/@jasminegump/passing-data-between-a-parent-and-child-in-react-deea2ec8e654.

Using destructuring, we can now add together the props like then:

            import React, { useRef, useState } from "react";  const DEFAULT_MAX_FILE_SIZE_IN_BYTES = 500000;  const FileUpload = ({   label,   updateFilesCb,   maxFileSizeInBytes = DEFAULT_MAX_FILE_SIZE_IN_BYTES,   ...otherProps }) => {   const fileInputField = useRef(null);   const [files, setFiles] = useState({});    return (    <input blazon="file" ref={fileInputField} />   ) }  export default FileUpload;                      

Enter fullscreen manner Exit fullscreen way

"Why are we using the spread syntax when destructuring otherProps?"

When destructuring, nosotros can assign all other values that were not explicitly destructured to a variable.

            allow props = { a: one, b: 2, c: 3}; allow {a, ...otherProps} = props;  //a = 1 //otherProps = {b: 2, c: 3};                      

Enter fullscreen mode Exit fullscreen mode

In this instance, for any props that we do not destructure, they volition be assigned to the otherProps variable. We will see the utilize of this otherProps variable later.

HTML

For the icons shown in Figure ane, nosotros volition be using Font Awesome. To import it, add together the following in the head tag in the public/alphabetize.html file:

            <link  rel="stylesheet"  href="https://cdnjs.cloudflare.com/ajax/libs/font-crawly/5.13.0/css/all.min.css" />                      

Enter fullscreen mode Exit fullscreen way

From Effigy 1, it is evident nosotros can split the HTML for the component into 2 main parts.

Main parts of component

Hither is the component with the HTML for the kickoff office:

            import React, { useRef, useState } from "react";  const DEFAULT_MAX_FILE_SIZE_IN_BYTES = 500000;  const FileUpload = ({   label,   updateFilesCb,   maxFileSizeInBytes = DEFAULT_MAX_FILE_SIZE_IN_BYTES,   ...otherProps }) => {   const fileInputField = useRef(nix);   const [files, setFiles] = useState({});    render (       <section>         <label>{label}</label>         <p>Drag and driblet your files anywhere or</p>         <push button type="push">           <i className="fas fa-file-upload" />           <span> Upload {otherProps.multiple ? "files" : "a file"}</span>         </button>         <input           type="file"           ref={fileInputField}           title=""           value=""           {...otherProps}         />       </section>         ); }  consign default FileUpload;                      

Enter fullscreen mode Leave fullscreen manner

Earlier, we discussed that any props that we don't destructure will be assigned to the otherProps variable (i.due east. any prop other than label, updateFilesCb, maxFileSizeInBytes). In the code above, we are taking that otherProps variable and passing it to the file input tag. This was washed and then that we tin can add together attributes to the file input tag from the parent component via props.

"Why are nosotros setting the championship and value attribute to ""?"

Setting the championship aspect to "" gets rid of the text that shows up past default when hovering over the input tag ("No file chosen").

Setting the value aspect to "" fixes an edge case where uploading a file right subsequently removing it does not alter the files state. After, nosotros will see that the files state only changes once the value of the input tag changes. This issues occurs because when nosotros remove a file, the input tag'southward value does not change. Since land changes re-render HTML, setting the value aspect to "" resets the input tag's value on each files country alter.

Before nosotros write the HTML for the second part, keep in mind that React just allows for returning one parent element from a component. Thus, we volition enclose both parts in a <></> tag.

Here is the component with the HTML for both parts:

            import React, { useRef, useState } from "react";  const DEFAULT_MAX_FILE_SIZE_IN_BYTES = 500000; const KILO_BYTES_PER_BYTE = 1000;  const convertBytesToKB = (bytes) => Math.round(bytes / KILO_BYTES_PER_BYTE);  const FileUpload = ({   label,   updateFilesCb,   maxFileSizeInBytes = DEFAULT_MAX_FILE_SIZE_IN_BYTES,   ...otherProps }) => {   const fileInputField = useRef(null);   const [files, setFiles] = useState({});    return (     <>       <section>         <label>{characterization}</label>         <p>Elevate and drib your files anywhere or</p>         <push blazon="button">           <i className="fas fa-file-upload" />           <bridge> Upload {otherProps.multiple ? "files" : "a file"}</span>         </button>         <input           type="file"           ref={fileInputField}           title=""           value=""           {...otherProps}         />       </section>        {/*2nd role starts here*/}       <article>         <span>To Upload</bridge>         <section>           {Object.keys(files).map((fileName, index) => {             let file = files[fileName];             let isImageFile = file.type.split("/")[0] === "image";             return (               <department key={fileName}>                 <div>                   {isImageFile && (                     <img                       src={URL.createObjectURL(file)}                       alt={`file preview ${index}`}                     />                   )}                   <div isImageFile={isImageFile}>                     <bridge>{file.name}</bridge>                     <aside>                       <span>{convertBytesToKB(file.size)} kb</span>                       <i className="fas fa-trash-alt" />                     </aside>                   </div>                 </div>               </section>             );           })}         </department>       </article>     </>   ); };  export default FileUpload;                      

Enter fullscreen mode Exit fullscreen fashion

In the second part of the HTML, nosotros are iterating through each file in the files state and displaying the file name, size in KB, and an image preview if the file type is image/* (i.e. png, jpg...etc).

To display an image preview, we are using the URL.createObjectURL function. The createObjectURL function takes an object, which in this instance is a File object, and returns a temporary URL for accessing the file. We can and so set that URL to src attribute of an img tag.

Styling

Nosotros will now utilise the styled-components package we installed before.

Add the following in the file-upload.styles.js file:

            import styled from "styled-components";  export const FileUploadContainer = styled.section`   position: relative;   margin: 25px 0 15px;   edge: 2px dotted lightgray;   padding: 35px 20px;   border-radius: 6px;   display: flex;   flex-management: cavalcade;   align-items: center;   background-colour: white; `;  export const FormField = styled.input`   font-size: 18px;   display: block;   width: 100%;   edge: none;   text-transform: none;   position: accented;   acme: 0;   left: 0;   correct: 0;   bottom: 0;   opacity: 0;    &:focus {     outline: none;   } `;  export const InputLabel = styled.label`   top: -21px;   font-size: 13px;   color: black;   left: 0;   position: absolute; `;  export const DragDropText = styled.p`   font-weight: bold;   letter-spacing: 2.2px;   margin-superlative: 0;   text-align: center; `;  export const UploadFileBtn = styled.button`   box-sizing: border-box;   advent: none;   groundwork-colour: transparent;   border: 2px solid #3498db;   cursor: pointer;   font-size: 1rem;   line-height: ane;   padding: 1.1em 2.8em;   text-align: center;   text-transform: uppercase;   font-weight: 700;   edge-radius: 6px;   color: #3498db;   position: relative;   overflow: hidden;   z-alphabetize: 1;   transition: color 250ms ease-in-out;   font-family: "Open Sans", sans-serif;   width: 45%;   display: flex;   marshal-items: center;   padding-right: 0;   justify-content: heart;    &:after {     content: "";     position: absolute;     display: block;     top: 0;     left: l%;     transform: translateX(-50%);     width: 0;     height: 100%;     background: #3498db;     z-alphabetize: -1;     transition: width 250ms ease-in-out;   }    i {     font-size: 22px;     margin-correct: 5px;     edge-right: 2px solid;     position: absolute;     top: 0;     bottom: 0;     left: 0;     right: 0;     width: 20%;     display: flex;     flex-direction: column;     justify-content: center;   }    @media just screen and (max-width: 500px) {     width: 70%;   }    @media simply screen and (max-width: 350px) {     width: 100%;   }    &:hover {     color: #fff;     outline: 0;     background: transparent;      &:after {       width: 110%;     }   }    &:focus {     outline: 0;     background: transparent;   }    &:disabled {     opacity: 0.four;     filter: grayscale(100%);     arrow-events: none;   } `;  export const FilePreviewContainer = styled.commodity`   margin-bottom: 35px;    span {     font-size: 14px;   } `;  export const PreviewList = styled.section`   display: flex;   flex-wrap: wrap;   margin-top: 10px;    @media merely screen and (max-width: 400px) {     flex-direction: column;   } `;  export const FileMetaData = styled.div`   brandish: ${(props) => (props.isImageFile ? "none" : "flex")};   flex-direction: cavalcade;   position: absolute;   top: 0;   left: 0;   right: 0;   bottom: 0;   padding: 10px;   edge-radius: 6px;   color: white;   font-weight: bold;   background-colour: rgba(five, five, 5, 0.55);    aside {     margin-superlative: automobile;     display: flex;     justify-content: space-between;   } `;  consign const RemoveFileIcon = styled.i`   cursor: pointer;    &:hover {     transform: scale(1.three);   } `;  export const PreviewContainer = styled.section`   padding: 0.25rem;   width: 20%;   acme: 120px;   border-radius: 6px;   box-sizing: border-box;    &:hover {     opacity: 0.55;      ${FileMetaData} {       display: flex;     }   }    & > div:start-of-type {     height: 100%;     position: relative;   }    @media only screen and (max-width: 750px) {     width: 25%;   }    @media only screen and (max-width: 500px) {     width: 50%;   }    @media only screen and (max-width: 400px) {     width: 100%;     padding: 0 0 0.4em;   } `;  consign const ImagePreview = styled.img`   border-radius: 6px;   width: 100%;   height: 100%; `;                      

Enter fullscreen mode Get out fullscreen mode

When using styled-components, we are creating components that render an HTML tag with some styles. For example, the ImagePreview is a component that renders an img tag with the styles within the tagged template literal.

Since nosotros are creating components, we can pass props to information technology and access it when writing the styles (e.thou. FileMetaData in the example above).

We have at present finished the styling and adding drag and drop.

"But wait, when did we add together elevate and drib?"

Past default, the file input tag supports drag and driblet. We simply just styled the input tag and fabricated it absolutely positioned (refer to FormField above).

To utilise the styles we wrote, import all the styled components and replace the HTML in the file-upload.component.jsx file.

            import React, { useRef, useState } from "react"; import {   FileUploadContainer,   FormField,   DragDropText,   UploadFileBtn,   FilePreviewContainer,   ImagePreview,   PreviewContainer,   PreviewList,   FileMetaData,   RemoveFileIcon,   InputLabel } from "./file-upload.styles";  const DEFAULT_MAX_FILE_SIZE_IN_BYTES = 500000; const KILO_BYTES_PER_BYTE = grand;  const convertBytesToKB = (bytes) =>   Math.round(bytes / KILO_BYTES_PER_BYTE);  const FileUpload = ({   label,   updateFilesCb,   maxFileSizeInBytes = DEFAULT_MAX_FILE_SIZE_IN_BYTES,   ...otherProps }) => {   const fileInputField = useRef(nil);   const [files, setFiles] = useState({});      return (     <>       <FileUploadContainer>         <InputLabel>{label}</InputLabel>         <DragDropText>Drag and drop your files anywhere or</DragDropText>         <UploadFileBtn blazon="button">           <i className="fas fa-file-upload" />           <span> Upload {otherProps.multiple ? "files" : "a file"}</span>         </UploadFileBtn>         <FormField           type="file"           ref={fileInputField}           title=""           value=""           {...otherProps}         />       </FileUploadContainer>       <FilePreviewContainer>         <span>To Upload</bridge>         <PreviewList>           {Object.keys(files).map((fileName, index) => {             let file = files[fileName];             allow isImageFile = file.blazon.divide("/")[0] === "image";             return (               <PreviewContainer key={fileName}>                 <div>                   {isImageFile && (                     <ImagePreview                       src={URL.createObjectURL(file)}                       alt={`file preview ${index}`}                     />                   )}                   <FileMetaData isImageFile={isImageFile}>                     <span>{file.proper name}</bridge>                     <aside>                       <span>{convertBytesToKB(file.size)} kb</span>                       <RemoveFileIcon                         className="fas fa-trash-alt"                       />                     </aside>                   </FileMetaData>                 </div>               </PreviewContainer>             );           })}         </PreviewList>       </FilePreviewContainer>     </>   ); }  export default FileUpload;                      

Enter fullscreen mode Exit fullscreen mode

Functionality

We are almost finished with the file-upload component, we just need to add functions then that files land can be modified.

Earlier we created a DOM reference using the useRef hook. Nosotros volition now apply that to open the file explorer once the "Upload Files" push is clicked. To do this, add the following role within the component:

            const handleUploadBtnClick = () => {   fileInputField.current.click(); };                      

Enter fullscreen mode Get out fullscreen mode

We also need to add together an onClick attribute to the UploadFileBtn component to trigger the function above.

            <UploadFileBtn type="button" onClick={handleUploadBtnClick}>                      

Enter fullscreen mode Exit fullscreen mode

To process the files selected by the user once the "Upload Files" button is clicked, we need to add an onChange attribute to the FormField component.

            <FormField   type="file"   ref={fileInputField}   onChange={handleNewFileUpload}   title=""   value=""   {...otherProps} />                      

Enter fullscreen style Exit fullscreen mode

Like with any DOM event (e.g. onClick), the function to handle the event will have access to the event object. And so, the handleNewFileUpload part will have the effect object every bit its start parameter.

                          const handleNewFileUpload = (eastward) => {     const { files: newFiles } = e.target;     if (newFiles.length) {       allow updatedFiles = addNewFiles(newFiles);       setFiles(updatedFiles);       callUpdateFilesCb(updatedFiles);     }   };                      

Enter fullscreen mode Exit fullscreen manner

In the function in a higher place, we access the files selected past the user from the eastward.target.files holding then pass it to a role called addNewFiles. Then, we take the return value from addNewFiles and pass information technology to the setFiles to update the files state. Since any changes to the files state must exist sent to the parent component, nosotros need to call the callUpdateFilesCb office.

The addNewFiles function takes a FileList object (east.target.files above returns a FileList), iterates through it, and returns an object where the key is the file proper name and the value is the File object.

                          const addNewFiles = (newFiles) => {     for (let file of newFiles) {       if (file.size <= maxFileSizeInBytes) {         if (!otherProps.multiple) {           return { file };         }         files[file.proper name] = file;       }     }     return { ...files };   };                      

Enter fullscreen mode Exit fullscreen mode

"Why are checking if in that location is not a multiple property in otherProps?"

Equally explained earlier, we are using the otherProps variable to add attributes to the file input tag. And then, if we don't laissez passer a multiple prop to the file upload component, then the file input tag does not allow for selecting multiple files. Put but, if there is a multiple prop, selected files will get added to the files land. Otherwise, selecting a new file volition remove the previous files state and replace it with the newly selected file.

The callUpdateFilesCb office takes the value returned from addNewFiles, converts the files state to an array and calls the updateFilesCb function (from the props).

"Why do we pass updatedFiles to callUpdateFilesCb when we could just use the files state inside the function?"

Since React state updates are asynchronous, at that place is no guarantee that when the callUpdateFilesCb gets called, the files state will accept inverse.

"Why practice nosotros have to catechumen the files land to an array?"

We don't! However, when uploading files in the files state to some third political party service (e.g. Firebase Deject Storage), it's easier to piece of work with arrays.

            const convertNestedObjectToArray = (nestedObj) =>   Object.keys(nestedObj).map((primal) => nestedObj[key]);  const callUpdateFilesCb = (files) => {   const filesAsArray = convertNestedObjectToArray(files);   updateFilesCb(filesAsArray); };                      

Enter fullscreen mode Exit fullscreen mode

To remove a file, nosotros first demand to add an onClick attribute to the RemoveFileIcon component.

            <RemoveFileIcon   className="fas fa-trash-alt"   onClick={() => removeFile(fileName)} />                      

Enter fullscreen mode Go out fullscreen mode

The removeFile function will have a file name, delete it from the files state, update the files land, and inform the parent component of the changes.

            const removeFile = (fileName) => {   delete files[fileName];   setFiles({ ...files });   callUpdateFilesCb({ ...files }); };                      

Enter fullscreen mode Get out fullscreen mode

Here is the component with all the functions above:

            import React, { useRef, useState } from "react"; import {   FileUploadContainer,   FormField,   DragDropText,   UploadFileBtn,   FilePreviewContainer,   ImagePreview,   PreviewContainer,   PreviewList,   FileMetaData,   RemoveFileIcon,   InputLabel } from "./file-upload.styles";  const KILO_BYTES_PER_BYTE = 1000; const DEFAULT_MAX_FILE_SIZE_IN_BYTES = 500000;  const convertNestedObjectToArray = (nestedObj) =>   Object.keys(nestedObj).map((primal) => nestedObj[key]);  const convertBytesToKB = (bytes) => Math.circular(bytes / KILO_BYTES_PER_BYTE);  const FileUpload = ({   label,   updateFilesCb,   maxFileSizeInBytes = DEFAULT_MAX_FILE_SIZE_IN_BYTES,   ...otherProps }) => {   const fileInputField = useRef(cypher);   const [files, setFiles] = useState({});    const handleUploadBtnClick = () => {     fileInputField.current.click();   };    const addNewFiles = (newFiles) => {     for (allow file of newFiles) {       if (file.size < maxFileSizeInBytes) {         if (!otherProps.multiple) {           return { file };         }         files[file.proper noun] = file;       }     }     return { ...files };   };    const callUpdateFilesCb = (files) => {     const filesAsArray = convertNestedObjectToArray(files);     updateFilesCb(filesAsArray);   };    const handleNewFileUpload = (due east) => {     const { files: newFiles } = eastward.target;     if (newFiles.length) {       let updatedFiles = addNewFiles(newFiles);       setFiles(updatedFiles);       callUpdateFilesCb(updatedFiles);     }   };    const removeFile = (fileName) => {     delete files[fileName];     setFiles({ ...files });     callUpdateFilesCb({ ...files });   };    return (     <>       <FileUploadContainer>         <InputLabel>{characterization}</InputLabel>         <DragDropText>Drag and drop your files anywhere or</DragDropText>         <UploadFileBtn type="push" onClick={handleUploadBtnClick}>           <i className="fas fa-file-upload" />           <bridge> Upload {otherProps.multiple ? "files" : "a file"}</span>         </UploadFileBtn>         <FormField           type="file"           ref={fileInputField}           onChange={handleNewFileUpload}           title=""           value=""           {...otherProps}         />       </FileUploadContainer>       <FilePreviewContainer>         <span>To Upload</span>         <PreviewList>           {Object.keys(files).map((fileName, index) => {             let file = files[fileName];             let isImageFile = file.type.dissever("/")[0] === "image";             return (               <PreviewContainer key={fileName}>                 <div>                   {isImageFile && (                     <ImagePreview                       src={URL.createObjectURL(file)}                       alt={`file preview ${index}`}                     />                   )}                   <FileMetaData isImageFile={isImageFile}>                     <bridge>{file.name}</span>                     <aside>                       <span>{convertBytesToKB(file.size)} kb</span>                       <RemoveFileIcon                         className="fas fa-trash-alt"                         onClick={() => removeFile(fileName)}                       />                     </aside>                   </FileMetaData>                 </div>               </PreviewContainer>             );           })}         </PreviewList>       </FilePreviewContainer>     </>   ); };  export default FileUpload;                      

Enter fullscreen mode Get out fullscreen mode

Use Example

Let's now use the file upload component in App component to see it in action!

In the App.js file, nosotros will create a simple form and add state to store the form data.

            import React, { useState } from "react";  part App() {   const [newUserInfo, setNewUserInfo] = useState({     profileImages: []   });    const handleSubmit = (event) => {     upshot.preventDefault();     //logic to create a new user...   };    render (     <div>       <form onSubmit={handleSubmit}>         <button type="submit">Create New User</push button>       </form>     </div>   ); } export default App;                      

Enter fullscreen style Exit fullscreen mode

At present to add the file upload component.

            import React, { useState } from "react"; import FileUpload from "./components/file-upload/file-upload.component";  function App() {   const [newUserInfo, setNewUserInfo] = useState({     profileImages: []   });    const handleSubmit = (consequence) => {     event.preventDefault();     //logic to create a new user...   };    render (     <div>       <grade onSubmit={handleSubmit}>         <FileUpload           accept=".jpg,.png,.jpeg"           label="Contour Image(s)"           multiple         />         <button blazon="submit">Create New User</button>       </form>     </div>   ); }  export default App;                      

Enter fullscreen style Get out fullscreen fashion

Notice nosotros have non added the updateFilesCb prop yet. Before we tin do that, we need to create a function that updates only the profileImages property of the newUserInfo state.

            const updateUploadedFiles = (files) =>     setNewUserInfo({ ...newUserInfo, profileImages: files });                      

Enter fullscreen mode Exit fullscreen style

We will now pass this office every bit the updateFilesCb prop. And so, whatsoever time the files state changes in the file upload component, information technology will be saved in the profileImages holding of the newUserInfo land.

            import React, { useState } from "react"; import FileUpload from "./components/file-upload/file-upload.component";  office App() {   const [newUserInfo, setNewUserInfo] = useState({     profileImages: []   });    const updateUploadedFiles = (files) =>     setNewUserInfo({ ...newUserInfo, profileImages: files });    const handleSubmit = (event) => {     upshot.preventDefault();     //logic to create new user...   };    return (     <div>       <grade onSubmit={handleSubmit}>         <FileUpload           have=".jpg,.png,.jpeg"           label="Profile Paradigm(s)"           multiple           updateFilesCb={updateUploadedFiles}         />         <button type="submit">Create New User</push>       </grade>     </div>   ); }  export default App;                      

Enter fullscreen style Exit fullscreen mode

"Why are we passing the take and multiple prop to the file upload component?"

Since whatever boosted props volition go passed to the file input tag, the file input tag volition have an accept and multiple attribute.

The multiple aspect allows a user to select multiple files in the file explorer.

The have attribute prevents users from selecting file types different from the ones specified (i.e. jpg, png, jpeg in this case).

Now that we are finished, run npm starting time and visit localhost:3000. The following should announced:

Using the file upload component in a form

For reference, the lawmaking can exist establish at
https://github.com/Chandra-Panta-Chhetri/react-file-upload-tutorial.

goodwindistle.blogspot.com

Source: https://dev.to/chandrapantachhetri/responsive-react-file-upload-component-with-drag-and-drop-4ef8

0 Response to "Creating a React Component That Allows Csv and Txt File Upload"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel