ISBN
。
//submitting the forms
async function onSubmit(data: BookInferSchema) {
try {
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(
key,
value instanceof Date ? value.toISOString() : value.toString()
);
});
//sending the formData to the action.ts for submitting the forms
const response = action(formData) as {
error?: string;
message?: string;
} | void;
//Error or success messages for any submissions and any errors/success from the server
if (response?.error) {
toast({
title: "Error",
description: `An error occurred: ${response.error}`,
});
} else {
//after submitting the form, reset the form
// form.reset();
}
} catch {
toast({
title: "Error",
description: "An unexpected error occured.",
});
}
}
这是我的片段,我在其中验证并将书插入数据库:
action.ts
我尝试了什么:我尝试返回ISBN:
const validatedFields = BookSchema.safeParse({
ISBN: formData.get("ISBN"),
//...other fields
});
if (!validatedFields.success) {
console.error("Validation Errors:", validatedFields.error.format());
return {
errors: validatedFields.error.flatten().fieldErrors,
};
}
const { ISBN } = validatedFields.data;
const supabase = createClient();
const { data, error } = await (await supabase)
.from('books')
.insert({
isbn: ISBN,
// ... other fields
});
if (error) {
return {
error: true,
message: error.message,
};
}
return {
error: false,
message: 'Book updated successfully',
};
在此处使用它,在检查
const successMessage = {
error: false,
message: "Book updated successfully",
ISBN,
};
return successMessage;
的值时,它将显示出不确定的。
2nd尝试: 我将此代码放在提交后的!response?.error
response
但它将显示此应用程序错误,这就是控制台将与我重定向:Https://nextjs.s.org/docs/messages/sync-dynamic-apis 这是编辑书页链接:
action.ts
:我确定我可以访问此页面,因为我还在处理一个重定向页面以查看每本书。
// Perform the redirect after returning the success message
redirect(`/admin/books/${ISBN}/edit`);
第三尝试:但是,这是一种更好的方法?我应该把它放在/admin/books/${id}/edit
中还是只是放在上面?
const BookEdit = async (props: { params: Promise<{ id: string }> }) => {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return redirect("/login");
}
const params = await props.params;
const id = params.id;
const books = await fetchAllBooks(id);
const bookData = books ? books[0] : null;
return <h1>Edit Book {JSON.stringify(bookData, null, 2)}</h1>;
};
export default BookEdit;
您在正确的轨道上,您的第三次尝试是最接近一个好的解决方案。让我们分解为什么您的其他尝试失败以及如何完善工作解决方案。
当您的前两个尝试失败时:
直接返回ISBN:
不确定的问题可能是由于您如何处理
useEffect
useEffect(() => {
if (state?.message) {
toast({
title: state?.error ? "Error" : "Success",
description: state?.message,
});
}
}, [state]);
if (state?.id) {
router.push(`/admin/books/${state.id}/edit`);
}
。如果要访问ISBN,则需要包含在该类型定义中。
,您也不在等待动作函数的响应。因此,响应将始终是无效的或不确定的。
response?.ISBN
action(formData)
:{ error?: string; message?: string; } | void
在Next.js应用程序路由器中必须在服务器组件的渲染阶段中调用。直接在渲染阶段之外的操作函数(也是服务器功能)中直接调用它会导致“同步动态 - 痛苦”错误。这是因为Next.js需要控制重定向正确工作的渲染流。
redirect()
action.ts
和redirect()
的第三种方法是操作后最适合客户端导航的方法。这是一个细分和一些改进:
useEffect
useEffect
type安全:
现在,客户端组件中的响应类型定义现在包括
router.push
,确保Typescript知道ISBN。
现在正确键入状态变量。
CLEAR国家管理:
使用// action.ts
"use server";
import { z } from "zod";
import { createClient } from "@/lib/supabase-server";
import { revalidatePath } from "next/cache";
const BookSchema = z.object({
ISBN: z.string(),
// ... other fields
});
export async function action(formData: FormData) {
const validatedFields = BookSchema.safeParse({
ISBN: formData.get("ISBN"),
// ... other fields
});
if (!validatedFields.success) {
console.error("Validation Errors:", validatedFields.error.format());
return {
errors: validatedFields.error.flatten().fieldErrors,
};
}
const { ISBN } = validatedFields.data;
const supabase = createClient();
const { error } = await supabase
.from("books")
.insert({
isbn: ISBN,
// ... other fields
});
if (error) {
return {
error: true,
message: error.message,
};
}
revalidatePath('/admin/books');
return {
error: false,
message: "Book updated successfully",
id: ISBN, // Return the ISBN as 'id'
};
}
"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { toast } from "@/components/ui/use-toast"; // Assuming you have a toast component
import { BookInferSchema } from "@/lib/zod-schema";
import { action } from "./action";
function BookForm() {
const router = useRouter();
const [state, setState] = useState<{
error?: boolean;
message?: string;
id?: string;
} | null>(null);
async function onSubmit(data: BookInferSchema) {
try {
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(
key,
value instanceof Date ? value.toISOString() : value.toString()
);
});
const response = (await action(formData)) as {
error?: boolean;
message?: string;
id?: string;
};
setState(response);
} catch (error) {
toast({
title: "Error",
description: "An unexpected error occurred.",
});
}
}
useEffect(() => {
if (state?.message) {
toast({
title: state?.error ? "Error" : "Success",
description: state?.message,
});
}
if (state?.id) {
router.push(`/admin/books/${state.id}/edit`);
}
}, [state, router]);
// Your form rendering here...
return (
<div>
<form onSubmit={e=>{
e.preventDefault();
const bookData:BookInferSchema = {
ISBN: "123456789",
//all the other form data.
}
onSubmit(bookData);
}}>
<button type="submit">Submit</button>
</form>
</div>
)
}
export default BookForm;
响应中管理action
是一种处理异步结果的干净且可预测的方法。
id?: string
依赖关系数组:依赖性数组包括
useState
,以确保效果重新运行,如果路由器实例更改(尽管不太可能)。
state
已添加到action.ts文件中。这允许显示所有书籍的页面都可以使用新添加的书进行更新。
现在正在等待操作函数调用,在Onsubmit函数内部。这很重要。
action
useEffect
确保导航发生在组件渲染并已更新状态后发生。IT允许您执行客户端导航。 这种方法为您的下一个申请中的表单提交和重定向提供了强大且可维护的解决方案。