Reputation: 173
I am trying to call a method in React TypeScript on the onChange
Event of a MUI Input field.
Unfortunately I get the following Error on the onChange
:
Type '(event: { target: { files: any[]; }; }) => void' is not assignable to type 'ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement>'. Types of parameters 'event' and 'event' are incompatible. Type 'ChangeEvent<HTMLTextAreaElement | HTMLInputElement>' is not assignable to type '{ target: { files: any[]; }; }'. Types of property 'target' are incompatible. Type 'EventTarget & (HTMLTextAreaElement | HTMLInputElement)' is not assignable to type '{ files: any[]; }'. Property 'files' is missing in type 'EventTarget & HTMLTextAreaElement' but required in type '{ files: any[]; }'.
I'm trying to access the state and later-on call the method by onChange
.
Also important for you guys that I don't have much experience in File Upload and Save in React TypeScript with my API in JS it works but in TypeScript not I also went through 100 Tutorials but nothing helped me.
import axios from "axios";
import React from "react";
import { Input } from "@mui/material";
// export class FileUpload extends Component {
const FileUpload: React.FC = () => {
const [selectedFile] = React.useState<Blob>(new Blob);
// const [users] = React.useState<Blob | string>("");
function onFileChange(event: { target: { files: any[]; }; }): void {
// function onFileChange(event: { target: { files: any[]; }; }): void {
React.useState({ selectedFile: event.target.files[0] });
}
// On file upload (click the upload button)
async function onFileUpload() {
// Create an object of formData
const formData = new FormData();
// Update the formData object
formData.append(
"File",
selectedFile,
selectedFile.text.toString()
);
// Details of the uploaded file
console.log(selectedFile);
// Request made to the backend api
// Send formData object
try {
const responseData = await axios.post("https://localhost:7047/File/Upload", formData);
console.log(responseData);
} catch (ex) {
console.log(ex);
}
}
return (
<div>
<Input onChange={onFileChange} />
<Input type="button" value="upload" onClick={onFileUpload} />
</div>
);
};
export default FileUpload;
Upvotes: 0
Views: 2260
Reputation: 186984
Material UI declares the type of the onChange
prop as:
onChange?: React.ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement> | undefined
You can discover this by mousing over onChange
and you will see the reported type.
That mean that it handles a text area, or an input tag. This means your event handler needs to handle both as well. And the problem here is that only a HTMLInputElement
with a type of file
will have a files
property.
And in your code, if files
was missing, it would crash.
So first you need to declare the event type properly:
function onFileChange(event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>): void {
//...
}
Then you need to make sure the files
property exists before you use it.
function onFileChange(event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>): void {
if ('files' in event.target) {
React.useState({ selectedFile: event.target.files?.[0] });
}
}
Now you only access the files
it it exists, and you use the ?.
to only drill into if it is not null
or undefined
.
Playground with no type type errors
Lastly, the usage of useState
conditionally not correct here. You must follow the rules of hooks when using hooks like useState
and that will look more like this:
const [selectedFile, setSelectedFile] = React.useState<Blob>(new Blob);
function onFileChange(event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>): void {
if ('files' in event.target) {
setSelectedFile(event.target.files?.[0]);
}
}
Upvotes: 3