Как передать дополнительные аргументы действиям сервера Next.jsJavascript

Форум по Javascript
Ответить
Anonymous
 Как передать дополнительные аргументы действиям сервера Next.js

Сообщение Anonymous »

Я создаю страницу загрузки файлов в NextJs.
Я использовал useActionState вместе с InitialState.
ПроблемаЕсли после отправки в серверной части произошла ошибка проверки, данные, за исключением файлов, возвращались во внешний интерфейс. поэтому пользователю приходится повторно выбирать их все.
Чтобы избежать такого поведения, я сохранил файлы в определенном состоянии (больше не во входных данных), это был лучший подход, поскольку я не могу переназначить данные в поле ввода типа файла.
Однако я не знаю, как прикрепить их к запросу, идущему к serverAction.
Что я пробовал
Я пытались сделать это следующим образом:

Код: Выделить всё

  const handleFormSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
files.forEach((file) => formData.append("proof", file));
formAction(formData);
};
Но после отправки я получаю эту ошибку, хотя все работает так, как ожидалось:

Код: Выделить всё

An async function was passed to useActionState, but it was dispatched outside of an action context. This is likely not what you intended.  Either pass the dispatch function to an `action` prop, or dispatch manually inside `startTransition`
Я пытался понять эту ошибку, но не смог.
Цель/Ожидание
  • Как упоминалось выше, я хочу хранить файлы до тех пор, пока они не будут успешно загружены в облако.
  • В случае успеха я хочу сбросить состояния и удалить файлы из состояния.
Мой компонент

Код: Выделить всё

"use client";
import { useActionState, useCallback, useEffect } from "react";
import submit from "./action";
import { twJoin } from "tailwind-merge";
import Main from "@/components/Main";
import { useLocale, useTranslations } from "next-intl";
import Dropzone from "./Dropzone";
import PageHeader from "@/components/PageHeader";
import HugeRoundedButton from "@/components/RoundedButton";
import { useState } from "react";
import { FileRejection } from "react-dropzone";

const initialState = {
zodErrors: null,
message: null,
success: false,
data: {
summary: "",
proof: [],
note: "",
},
};
interface PreviewFile extends File {
preview: string;
}
const CostTracker = () => {
// States
const [formState, formAction, pending] = useActionState(submit, initialState);
const [files, setFiles] = useState([]);
const [rejectedFiles, setRejectedFiles] = useState([]);

const onDrop = useCallback(
(acceptedFiles: File[], rejectedFiles: FileRejection[]) => {
if (acceptedFiles.length > 0) {
setFiles((previousFiles) => [
...previousFiles,
...acceptedFiles.map((file) =>
Object.assign(file, {
preview: URL.createObjectURL(file),
})
),
]);
}

if (rejectedFiles.length > 0) {
setRejectedFiles((previousFiles) => [
...previousFiles,
...rejectedFiles,
]);
}
},
[]
);

const removeFile = (name: string) => {
// Revoke the data uris to avoid memory leaks
URL.revokeObjectURL(
files.find((file) => file.name === name)?.preview as string
);
setFiles((files) => files.filter((file) => file.name !== name));
};
const removeRejectedFile = (name: string) => {
setRejectedFiles((rejectedFiles) =>
rejectedFiles.filter(({ file }) => file.name !== name)
);
};

// Runs when the component unmounts
useEffect(() => {
// Make sure to revoke the data uris to avoid memory leaks, will run on unmount
return () => files.forEach((file) => URL.revokeObjectURL(file.preview));
}, [files]);

// Locale
const locale = useLocale();
const translations = useTranslations("cost_tracking_page");
const dir = locale === "ar" ? "rtl" : "ltr";

// Form State
const { data, zodErrors, message, success } = formState;

// Handle form submission
const handleFormSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
files.forEach((file) => formData.append("proof", file));
formAction(formData);
};

return (





{zodErrors?.summary && (

{zodErrors.summary}

)}




{zodErrors?.note && (

{zodErrors.note}

)}

aria-live="assertive"
className={twJoin(success ? "text-green-500" : "text-red-500")}
>
{message}




);
};

export default CostTracker;
Есть идеи, как этого добиться?
Спасибо всем.

Подробнее здесь: https://stackoverflow.com/questions/793 ... er-actions
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»