33
loading...
This website collects cookies to deliver better user experience
input
for the title, and a textarea
for the body.import React, { useState } from "react"; import Box from "@mui/material/Box";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
interface PostData {
title: string;
body: string;
}
const Form: React.FunctionComponent = () => {
const [formValues, setFormValues] = useState<PostData>({
title: "",
body: "",
});
// Handlers for the input
const handleTitleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setFormValues((prevFormValues) => ({
...prevFormValues,
title: event.target.value,
}));
};
const handleBodyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setFormValues((prevFormValues) => ({
...prevFormValues,
body: event.target.value,
}));
};
return (
<Box
display="flex"
height="100%"
flexDirection="column"
justifyContent="center"
alignItems="center"
>
<Box marginY={2}>
<TextField
onChange={handleTitleChange}
value={formValues.title}
label="Post Title"
name="title"
/>
</Box>
<Box marginY={2}>
<TextField
onChange={handleBodyChange}
multiline
minRows={5}
label="Post Body"
name="body"
/>
</Box>
<Box marginY={3}>
<Button onClick={() => console.log("submit")}>Submit Post </Button>
</Box>
</Box>
);
};
export default Form;
input
of type file
, wrapped in a Button
component ://Form.tsx
const Form: React.FunctionComponent = () => {
...
return (
...
<Box marginY={2}>
<TextField
onChange={handleBodyChange}
multiline
minRows={5}
label="Post Body"
name="body"
/>
</Box>
<Button variant="contained" component="label">
<input type="file" hidden />
</Button>
<Box marginY={3}>
<Button onClick={() => console.log("submit")}>Submit Post </Button>
</Box>
)
}
interface PostData {
title: string;
body: string;
image: File | null;
}
const Form: React.FunctionComponent = () => {
// Add an image attribute
// to our formData
const [formValues, setFormValues] = useState<PostData>({
title: "",
body: "",
image: null,
});
...
// Set up the handler
const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setFormValues((prevFormValues) => ({
...prevFormValues,
image: event.target.files ? event.target.files[0] : null,
}));
};
...
return (
...
<Button variant="contained" component="label">
{formValues.image?.name ?? "Upload File"}
{/* Bind the handler to the input */}
<input onChange={handleImageChange} type="file" hidden />
</Button>
...
)
}
image
attribute will be populated with a File object. This object has a lot of usefulproperties, like the name of the file, and its type. We can use them to display the name file currently selected by the user inside our button. Also note that target.files
is an array. Here we're only interested in the first value as we're only uploading one file, but the same method can be used with multiple files !const handleSubmit = async () => {
const formData = new FormData();
formData.append("title", formValues.title);
formData.append("body", formValues.body);
formValues.image && formData.append("image", formValues.image);
const response = await axios.post(<YOUR-API-ENDPOINT>, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
return response.data
};
FormData
object;onUploadProgress
: send event during the upload phase;onDownloadProgress
: during the download phase;// hooks.ts
import { useState } from "react";
import axios from "axios";
export const useUploadForm = (url: string) => {
const [isSuccess, setIsSuccess] = useState(false);
const [progress, setProgress] = useState(0);
const uploadForm = async (formData: FormData) => {
setIsLoading(true);
await axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
onUploadProgress: (progressEvent) => {
const progress = (progressEvent.loaded / progressEvent.total) * 50;
setProgress(progress);
},
onDownloadProgress: (progressEvent) => {
const progress = 50 + (progressEvent.loaded / progressEvent.total) * 50;
console.log(progress);
setProgress(progress);
},
});
setSuccess(true)
};
return { uploadForm, isSuccess, progress };
};
success
boolean we can use to do some conditionnal rendering. const Form: React.FunctionComponent = () => {
const { isSuccess, uploadForm, progress } = useUploadForm(
"http://localhost:5000/post"
);
...
const handleSubmit = async () => {
const formData = new FormData();
formData.append("title", formValues.title);
formData.append("body", formValues.body);
formValues.image && formData.append("image", formValues.image);
return await uploadForm(formData);
};
}
...
const Form: React.FunctionComponent = () => {
return (
...
<Box marginY={3}>
<Button onClick={handleSubmit}>Submit Post </Button>
<LinearProgress variant="determinate" value={progress} />
</Box>
)
}
isSuccess
indicator. But first well add an artificial pause after the request complete to let he user//hooks.ts
const uploadForm = async (formData: FormData) => {
...
await new Promise((resolve) => {
setTimeout(() => resolve("success"), 500);
});
setIsSuccess(true);
setProgress(0);
};
isSuccess
we can conditionnaly render a success message :{ isSuccess ? (
<Box color="success.main" display="flex">
<CheckIcon color="success" />
<Typography>Success</Typography>
</Box>
) : (
<>
<Button onClick={handleSubmit}>Submit Post </Button>
<LinearProgress variant="determinate" value={progress} />
</>
)}