我在尝试将Next.js服务器操作与useFormState(用于在客户端显示输入错误)和Typescript集成时遇到了麻烦。
根据他们的官方文档here,他们建议为服务器操作函数添加一个新的prop,例如:
export async function createInvoice(prevState: State, formData: FormData)
字符串
在他们的示例中,他们将服务器动作函数作为第一个参数添加到useFormState中,如下所示:
const [state, dispatch] = useFormState(createInvoice, initialState);
型
在我的情况下,这是:
const [state, dispatch] = useFormState(action, initialState);
型
其中action
是从表单页面接收的服务器操作函数。
Typescript抱怨action类型,如何修复它?
No overload matches this call.
Overload 1 of 2, '(action: (state: { message: null; errors: {}; }) => Promise<{ message: null; errors: {}; }>, initialState: { message: null; errors: {}; }, permalink?: string | undefined): [state: { message: null; errors: {}; }, dispatch: () => void]', gave the following error.
Argument of type '(prevState: State, formData: FormData) => void' is not assignable to parameter of type '(state: { message: null; errors: {}; }) => Promise<{ message: null; errors: {}; }>'.
Target signature provides too few arguments. Expected 2 or more, but got 1.
Overload 2 of 2, '(action: (state: { message: null; errors: {}; }, payload: FormData) => Promise<{ message: null; errors: {}; }>, initialState: { message: null; errors: {}; }, permalink?: string | undefined): [state: ...]', gave the following error.
Argument of type '(prevState: State, formData: FormData) => void' is not assignable to parameter of type '(state: { message: null; errors: {}; }, payload: FormData) => Promise<{ message: null; errors: {}; }>'.
Type 'void' is not assignable to type 'Promise<{ message: null; errors: {}; }>'.ts(2769)
(parameter) action: (prevState: State, formData: FormData) => void
型
遵循我的表单组件代码:
import { useFormState } from "react-dom";
import { State } from "@/types/formState";
type Props = {
children: React.ReactNode;
action: string | ((prevState: State, formData: FormData) => void) | undefined;
};
const Form = ({ children, action }: Props) => {
const initialState = { message: null, errors: {} };
const [state, dispatch] = useFormState(action, initialState);
return (
<form
action={dispatch}
className="w-full flex justify-center"
autoComplete="off"
>
<div className={`w-full`}>
{children}
</div>
</form>
);
};
export default Form;
型
调用上面Form组件的页面:
import { createUserAccount } from "@/actions/createUserAccount";
import Form, { Button, InputText } from "@/components/Form";
type Props = {};
const SignUpPage = (props: Props) => {
return (
<Form action={createUserAccount}>
<div className="items-center mb-4 flex relative">
<InputText
name="firstname"
type="text"
placeholder="Enter your first name"
required
/>
</div>
<div className="items-center mb-4 flex relative">
<InputText
name="lastname"
type="text"
placeholder="Enter your last name"
required
/>
</div>
<div className="items-center mb-4 flex relative">
<Button title="Join Now" type="submit" />
</div>
</Form>
);
};
export default SignUpPage;
型
我的服务器操作函数(createUserAccount
):
"use server";
import { State } from "@/types/formState";
import userAccountSchema from "@/validation/schemas/createUserAccount";
export async function createUserAccount(prevState: State, formData: FormData) {
const parsedData = userAccountSchema.safeParse({
firstname: formData.get("firstname"),
lastname: formData.get("lastname"),
});
// Check if the parsing was not successful
if (!parsedData.success) {
return {
errors: parsedData.error.flatten().fieldErrors,
};
}
// Process validated data
// ...
return { success: true };
}
型
代码返回的输入错误在测试时没有任何问题。问题显然只是关于 typescript 。
谢谢你,谢谢
编辑#1
关注我的包。json:
{
"name": "project_name",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "14.0.4",
"react": "^18.2.46",
"react-dom": "^18.2.18",
"sass": "^1.69.7",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20.10.6",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.0.1",
"eslint": "^8.56.0",
"eslint-config-next": "14.0.4",
"postcss": "^8.4.33",
"tailwindcss": "^3.4.0",
"typescript": "^5.3.3"
}
}
型
2条答案
按热度按时间r7knjye21#
action
prop 的正确签名应该是:字符串
它必须是一个函数,该函数必须返回一个新的State或一个新State的Promise。
它不可能是
string
。您可能认为它是一个字符串,因为您正在将回调传递给
<form action="...">
。在vanilla React中,你必须使用一个字符串作为表单操作,但在NextJS中,你可以传递函数。
并且action是一个必需的参数,所以它不能是
undefined
。zfycwa2u2#
在使用
useFormState
的服务器操作中,操作的第一个参数的类型和返回值的类型必须相同:字符串
prevState
的类型为State,因此返回值也应该相同型
这是因为
useFormState
类型是如何定义的:型