ric*_*rn1 10 validation reactjs next.js react-server-components next.js13
我很好奇我们如何能够访问 Next.js 13 的 alpha 版本服务器操作的返回值。这是Next 团队的文档供参考。
假设我有以下示例服务器操作来执行输入验证:
async function validation(formData: FormData) { // needs "formData" or else errors
'use server';
// Get the data from the submitted form
const data = formData?.get("str");
// Sanitize the data and put it into a "str" const
const str = JSON.stringify(data)
.replace(/['"]+/g, '')
// Self explanatory
if (!str) {
return { error: "String is Required" }
}
else if (!(/^[a-zA-Z0-9]{8}$/).test(str)) {
return { error : "Invalid String Format" }
}
// Using next/navigation, redirect to another dynamic page
// if the data is validated
await redirect(`/scan-code=${str}`)
return null;
}
Run Code Online (Sandbox Code Playgroud)
该动作与一个简单的形式挂钩:
<form action={validation}>
<label>
{error && error}
</label>
<input
placeholder="Enter String Here"
required
name="str"
/>
<button type="submit">
Submit
</button>
</form>
Run Code Online (Sandbox Code Playgroud)
在 Remix 中,这将是使用操作和 useFetcher() 挂钩的非常简单的情况,并且该操作本质上看起来是相同的,除了在组件本身中,您可以使用类似的东西
const fetcher = useFetcher()
进而
const error = fetcher.data?.error
并通过类似的方式处理 UI 中的错误
<label style={{ color: error ? 'red' : 'black' }}>
{error && error}
</label>
Run Code Online (Sandbox Code Playgroud)
但是,我实际上只是返回错误或重定向到正确的页面,而不是能够检索错误值并根据它们是否存在来呈现它们,因此 UI 中没有错误反馈。
当首先尝试使用操作时,还会出现类型错误,并且异步函数的承诺与元素上的操作属性的预期类型不匹配,该元素显然是一个字符串。
( TS2322: Type '(formData: FormData) => Promise<{ error: string; } | null>' is not assignable to type 'string')
我很好奇我在这里做错了什么,以及 Next 的服务器操作的 RemixuseFetcher()和useActionData()钩子的替代方案是什么,因为我觉得在上下文、本地存储或数据库中保留错误将是一个不必要的步骤。
任何和所有的帮助将不胜感激。谢谢你!
根据此GitHub 讨论中非常简洁的回复,您只能使用客户端呈现的表单来执行此操作。就我而言,我有一个服务器渲染的页面。该页面定义了一个内联服务器操作,然后将该操作传递给客户端呈现的表单。客户端渲染的表单用另一个async函数包装服务器操作,然后将新的包装函数传递给form['action']prop。
// app/whatever/new/client-rendered-form.tsx
"use client";
import { useState } from "react";
export default ClientRenderedForm({
serverAction
}: {
serverAction: (data: FormData) => Promise<unknown>
}) {
const [error, setError] = useState<unknown>();
return (
<form
action={async (data: FormData) => {
try {
await serverAction(data);
} catch (e: unknown) {
console.error(e);
setError(e);
}
}}
>
<label>
<span>Name</span>
<input name="name" />
</label>
<button type="submit">pull the lever!</button>
</form>
);
}
Run Code Online (Sandbox Code Playgroud)
// app/whatever/new/page.tsx
import { redirect } from "next/navigation";
import ClientRenderedForm from "./client-rendered-form";
export default WhateverNewPage() {
const serverAction = async (data: FormData) => {
"use server";
// i don't know why the 'use server' directive is required,
// but it is. this file is already executed on the server
//
// this function runs on the server. you may process the data
// however you'd like
//
// if this function throws, the client wrapper will catch
//
// when you are finished, you likely need to execute a
// `redirect()`. i don't know if the `return` keyword
// is required
return redirect("/somewhere/else");
};
return (
<div className="fancy-layout">
<ClientRenderedForm {...{ serverAction }} />
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
我希望这有帮助!这个新范例还处于早期阶段,因此文档尚未填写。
| 归档时间: |
|
| 查看次数: |
6255 次 |
| 最近记录: |