#reactjs #formik
#reactjs #formik
Вопрос:
Я реализовал многоступенчатую форму formik с помощью formik-wizard-form. Он отлично работает с другими входными данными, за исключением загрузки файла.
Я использую следующий код для загрузки файла:
<Form.Group controlId="upload">
<Col>
<div className="form-group files">
Add Attachments:
<input
type="file"
name="upload"
value={values.upload?.files }
onChange={event => {
setFieldValue("upload", event.currentTarget.files);
}}
multiple />
</div>
</Col>
</Form.Group>
Значения загрузки журнала консоли такие, как показано ниже.
Как мне передать загружаемые файлы на сервер?
Ответ №1:
Хитрость с файловыми вводами в соответствии с документами заключается в:
В React
<input type="file" />
всегда является неконтролируемым компонентом, поскольку его значение может быть установлено только пользователем, а не программно.
Таким образом, он использует свой собственный механизм наряду с реализациями безопасности браузера для установки значения отправленного файла. По соображениям безопасности вы не можете получить полный путь к файлу на локальном компьютере того, с которого он был отправлен, хотя мы можем использовать объект FileReader для асинхронного чтения содержимого файла, а затем использовать результат для заполнения значения и отправки его родительскому компоненту формы.
Бывают случаи, когда вы можете изменить значение ввода файла программно, например, на null, чтобы сбросить ваш ввод.
В своей многоступенчатой форме я использовал formik и material-ui. в нем есть поле (UploadFiled), которое type="file"
будет обернуто компонентом пользовательского поля. Всякий раз, когда дочерний компонент получает обновление, файл загружается, а родительский компонент узнает и начинает считывать содержимое указанного большого двоичного объекта, после завершения атрибут result содержит данные: URL, представляющий данные файла, будет установлен в качестве его значения. В настоящее время он принимает базу изображений на основе проверки, которая установлена для него с помощью Yup.
Традиционный тип application / json не поможет при загрузке изображения на ваш сервер, а FormData поможет. Вам нужно написать свой handleSubmit(), используя данные формы, и передать значения, обрабатываемые Formik.
Вы можете использовать любой из Fetch API или Axios для отправки POST-запроса на ваш сервис, зависит от ваших предпочтений.
const onSubmit = () => {
// Create an object of formData
const formData = new FormData();
// Update the formData object
formData.append("myFile", file, file.name);
// Details of the uploaded file
console.log(file);
// Request made to the backend api
// Send formData object
axios.post("api/uploadfile", formData);
};
// UploadForm.jsx
import React, { useState, useEffect } from "react";
import { Field, useField } from "formik";
import { Grid, FormHelperText } from "@material-ui/core";
import UploadField from "../../FormFields/UploadField";
import Thumb from "../Helper/Thumb";
const ImageForm = (props) => {
const {
formField: { image }
} = props;
const [field, meta, helper] = useField(image.name);
const { touched, error } = meta;
const { setValue } = helper;
const isError = touched amp;amp; error amp;amp; true;
const { value } = field;
const [fileName, setFileName] = useState(value.name);
const [file, setFile] = useState(value.file);
const [src, setSrc] = useState(value.src);
const _onChange = (e) => {
let reader = new FileReader();
let file = e.target.files[0];
if (file) {
reader.onloadend = () => setFileName(file.name);
if (file.name !== fileName) {
reader.readAsDataURL(file);
setSrc(reader);
setFile(file);
}
}
};
useEffect(() => {
if (file amp;amp; fileName amp;amp; src) {
setValue({ file: file, src: src, name: fileName });
console.log(fileName);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [src, fileName, file]);
return (
<React.Fragment>
<Grid container spacing={3} justify="center" alignItems="center">
<Grid item xs={12}>
<label>
{image.label}
</label>
<br />
<div
style={{
display: "flex",
justifyContent: "flex-start",
fontSize: "1.2em"
}}
>
<Field
variant="outlined"
field={field}
component={UploadField}
onChange={_onChange}
isError={isError}
/>
{isError amp;amp; <FormHelperText color={"red"}>{error}</FormHelperText>}
</div>
</Grid>
<Grid item>{file amp;amp; src amp;amp; <Thumb file={file} src={src}></Thumb>}</Grid>
</Grid>
</React.Fragment>
);
};
export default ImageForm;
// Поле для загрузки.jsx
import React from "react";
import { Field } from "formik";
const UploadField = ({
field,
form: { touched, errors },
name,
label,
isError,
...props
}) => {
return (
<>
<Field
variant="outlined"
name="uploader"
title={label}
type={"file"}
{...props}
/>
</>
);
};
export default UploadField;
Ссылка на Code Sandbox,
Комментарии:
1. Спасибо, ваше решение решает мою проблему 🙂
Ответ №2:
Formik не поддерживает загрузку файлов «из коробки». Итак, если вы загружаете файлы асинхронно, вам придется сделать что-то вроде этого:
const rebuildData = (values) => {
let formData = new FormData();
Object.keys(values).forEach(key => {
formData.append(key, values[key]);
});
return formData;
};
<Formik
onSubmit={values => {
const data = rebuildData(values);
axios({
method: 'post',
url: '/YOUR_ENDPOINT',
data
})
}
}
Не забудьте добавить остальные данные вашей формы в formData
.
Комментарии:
1. Хотите добавить детали к ответу, убедитесь, что задали заголовки для многоступенчатой загрузки в axios, чтобы фактически доставлять файлы.
2. @Darius в моем случае нет необходимости отправлять какие-либо дополнительные заголовки, но если вам нужно отправить заголовки, просто используйте
headers
ключ в объекте параметров запроса.3. Серверная часть @Darius на моем сервере каким-то образом «распознает»
formData
без каких-либо усилий со стороны интерфейса.4. Понял. Что касается меня, я сохранял данные в многоступенчатой форме, не имея «формы» для отправки, только значения. Так что, возможно, это было потому, что я отправлял не «форму», а значения с переменной «file» там.
Ответ №3:
Вы можете использовать setFieldValue из formik. ссылка: Formik
const _onChange = (e) => {
let reader = new FileReader();
let file = e.target.files[0];
if (file) {
reader.onloadend = () => setFileName(file.name);
if (file.name !== fileName) {
reader.readAsDataURL(file);
setSrc(reader);
setFieldValue('file',file);
}
}
};