Anonymous
Как загрузить файл при обновлении события onChange?
Сообщение
Anonymous » 06 янв 2025, 18:14
Я использую Nextjs и Resend для отправки электронных писем из разных форм. Все мои формы отправляют данные без проблем, за исключением одной, которая предполагает загрузку файла.
Вот как я создаю свои формы.
У меня есть Компонент FormGroup:
Код: Выделить всё
"use client";
import { useEffect, useState } from "react";
type FormGroupProps = {
label?: string;
inputType?: "input" | "textarea" | "select" | "file";
inputProps?:
| React.InputHTMLAttributes
| React.TextareaHTMLAttributes;
selectOptions?: Array;
error?: string;
};
export default function FormGroup({
label,
inputType = "input",
inputProps,
selectOptions = [],
error,
}: FormGroupProps) {
const [hasError, setHasError] = useState(false);
useEffect(() => {
setHasError(error !== undefined);
}, [error]);
return (
className={`form-group flex flex-col h-full gap-2.5 ${
inputProps?.className || ""
}`}
>
{label && (
{label}
)}
{inputType === "input" && (
)}
{error && {error}}
{inputType === "textarea" && (
)}
{inputType === "file" && (
)}
{inputType === "select" && (
{selectOptions?.map((option) => (
{option.label}
))}
)}
);
}
Затем у меня есть компонент GenericForm:
Код: Выделить всё
"use client";
import React, { useState } from "react";
import FormGroup from "./FormGroup";
import FormTitle from "./FormTitle";
interface GenericFormProps {
title: string;
fields: Array;
onSubmit: (data: T) => void;
errors: { [key in keyof T]?: string };
handleChange?: (event: React.ChangeEvent) => void;
}
interface FormData {
nombre: string;
apellido: string;
dni: string;
celular: string;
mail: string;
comentarios: string;
cv?: {
name: string;
type: string;
base64: string;
};
}
function GenericForm({
title,
fields,
onSubmit,
errors,
handleChange,
}: GenericFormProps) {
const initialFormData = {} as T;
const [formData, setFormData] = useState(initialFormData);
const combinedHandleChange = (event: React.ChangeEvent) => {
if (handleChange) {
handleChange(event);
}
const { name, value, files } = event.target as HTMLInputElement & {
files: FileList | null;
};
setFormData((prevData) => ({
...prevData,
[name]: files ? files[0] : value,
}));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
onSubmit(formData);
if (!Object.values(errors).some((error) => error !== undefined)) {
setFormData(initialFormData);
}
};
return (
{fields.map((field, index) => (
))}
Enviar
);
}
export default GenericForm;
И форма, которая не работает, — это TrabajaConNosotros.tsx:
Код: Выделить всё
"use client";
import GenericForm from "./GenericForm";
import TrabajaConNosotrosSchema from "@/schemes/trabaja-con-nosotros.scheme";
import handleSubmit from "@/utils/submitForm";
import { useState } from "react";
const TrabajaConNosotros = () => {
const fields = [
{ label: "Nombre", inputType: "input", name: "nombre" },
{ label: "Apellido", inputType: "input", name: "apellido" },
{ label: "DNI (sin puntos)", inputType: "input", name: "dni" },
{ label: "Celular", inputType: "input", name: "celular" },
{ label: "Mail", inputType: "input", name: "mail" },
{ label: "Comentarios", inputType: "textarea", name: "comentarios" },
{ label: "Adjuntar CV", inputType: "file", name: "cv" },
];
const [errors, setErrors] = useState({});
const [selectedFile, setSelectedFile] = useState(null);
const handleChange = (event: React.ChangeEvent) => {
const file = event.target.files?.[0];
if (file) {
setSelectedFile(file);
}
};
const readFileAsync = (file: File): Promise =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as string);
reader.onerror = reject;
reader.readAsDataURL(file);
});
const onSubmit = async (data: FormData) => {
if (selectedFile) {
try {
const base64 = await readFileAsync(selectedFile);
const formDataWithCV = {
...data,
cv: {
name: selectedFile.name,
type: selectedFile.type,
base64: base64.split(',')[1],
},
};
await handleSubmit(formDataWithCV, TrabajaConNosotrosSchema, 'trabajar_con_nosotros');
setErrors({});
} catch (err) {
console.error(err);
}
} else {
try {
await handleSubmit(data, TrabajaConNosotrosSchema, 'trabajar_con_nosotros');
setErrors({});
} catch (err) {
if (err.inner) {
const formErrors = err.inner.reduce((acc, currentError) => {
acc[currentError.path] = currentError.message;
return acc;
}, {});
setErrors(formErrors);
} else {
setErrors({ general: "Ha ocurrido un error desconocido" });
}
}
}
};
return (
);
};
export default TrabajaConNosotros;
Ошибка возникает, когда я выбираю файл для загрузки и сразу же на экране появляется следующая ошибка:
Код: Выделить всё
Uncaught DOMException: An attempt was made to use an object that is not, or is no longer, usable
Из этого сообщения об ошибке я предполагаю, что оно как-то связано с событием onChange, но понятия не имею, как это исправить.
Подробнее здесь:
https://stackoverflow.com/questions/793 ... ange-event
1736176462
Anonymous
Я использую Nextjs и Resend для отправки электронных писем из разных форм. Все мои формы отправляют данные без проблем, за исключением одной, которая предполагает загрузку файла. Вот как я создаю свои формы. У меня есть Компонент FormGroup: [code]"use client"; import { useEffect, useState } from "react"; type FormGroupProps = { label?: string; inputType?: "input" | "textarea" | "select" | "file"; inputProps?: | React.InputHTMLAttributes | React.TextareaHTMLAttributes; selectOptions?: Array; error?: string; }; export default function FormGroup({ label, inputType = "input", inputProps, selectOptions = [], error, }: FormGroupProps) { const [hasError, setHasError] = useState(false); useEffect(() => { setHasError(error !== undefined); }, [error]); return ( className={`form-group flex flex-col h-full gap-2.5 ${ inputProps?.className || "" }`} > {label && ( {label} )} {inputType === "input" && ( )} {error && {error}} {inputType === "textarea" && ( )} {inputType === "file" && ( )} {inputType === "select" && ( {selectOptions?.map((option) => ( {option.label} ))} )} ); } [/code] Затем у меня есть компонент GenericForm: [code]"use client"; import React, { useState } from "react"; import FormGroup from "./FormGroup"; import FormTitle from "./FormTitle"; interface GenericFormProps { title: string; fields: Array; onSubmit: (data: T) => void; errors: { [key in keyof T]?: string }; handleChange?: (event: React.ChangeEvent) => void; } interface FormData { nombre: string; apellido: string; dni: string; celular: string; mail: string; comentarios: string; cv?: { name: string; type: string; base64: string; }; } function GenericForm({ title, fields, onSubmit, errors, handleChange, }: GenericFormProps) { const initialFormData = {} as T; const [formData, setFormData] = useState(initialFormData); const combinedHandleChange = (event: React.ChangeEvent) => { if (handleChange) { handleChange(event); } const { name, value, files } = event.target as HTMLInputElement & { files: FileList | null; }; setFormData((prevData) => ({ ...prevData, [name]: files ? files[0] : value, })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); onSubmit(formData); if (!Object.values(errors).some((error) => error !== undefined)) { setFormData(initialFormData); } }; return ( {fields.map((field, index) => ( ))} Enviar ); } export default GenericForm; [/code] И форма, которая не работает, — это TrabajaConNosotros.tsx: [code]"use client"; import GenericForm from "./GenericForm"; import TrabajaConNosotrosSchema from "@/schemes/trabaja-con-nosotros.scheme"; import handleSubmit from "@/utils/submitForm"; import { useState } from "react"; const TrabajaConNosotros = () => { const fields = [ { label: "Nombre", inputType: "input", name: "nombre" }, { label: "Apellido", inputType: "input", name: "apellido" }, { label: "DNI (sin puntos)", inputType: "input", name: "dni" }, { label: "Celular", inputType: "input", name: "celular" }, { label: "Mail", inputType: "input", name: "mail" }, { label: "Comentarios", inputType: "textarea", name: "comentarios" }, { label: "Adjuntar CV", inputType: "file", name: "cv" }, ]; const [errors, setErrors] = useState({}); const [selectedFile, setSelectedFile] = useState(null); const handleChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { setSelectedFile(file); } }; const readFileAsync = (file: File): Promise => new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.onerror = reject; reader.readAsDataURL(file); }); const onSubmit = async (data: FormData) => { if (selectedFile) { try { const base64 = await readFileAsync(selectedFile); const formDataWithCV = { ...data, cv: { name: selectedFile.name, type: selectedFile.type, base64: base64.split(',')[1], }, }; await handleSubmit(formDataWithCV, TrabajaConNosotrosSchema, 'trabajar_con_nosotros'); setErrors({}); } catch (err) { console.error(err); } } else { try { await handleSubmit(data, TrabajaConNosotrosSchema, 'trabajar_con_nosotros'); setErrors({}); } catch (err) { if (err.inner) { const formErrors = err.inner.reduce((acc, currentError) => { acc[currentError.path] = currentError.message; return acc; }, {}); setErrors(formErrors); } else { setErrors({ general: "Ha ocurrido un error desconocido" }); } } } }; return ( ); }; export default TrabajaConNosotros; [/code] Ошибка возникает, когда я выбираю файл для загрузки и сразу же на экране появляется следующая ошибка: [code]Uncaught DOMException: An attempt was made to use an object that is not, or is no longer, usable[/code] Из этого сообщения об ошибке я предполагаю, что оно как-то связано с событием onChange, но понятия не имею, как это исправить. Подробнее здесь: [url]https://stackoverflow.com/questions/79333482/how-can-i-upload-a-file-when-updating-a-onchange-event[/url]