Myo*_*dan 11 typescript reactjs react-hook-form
如何将 Form 的类型继承给其子项?我想通过继承类型来使用名称中的自动建议功能。并且代码运行良好。但这并不能达到我想要的效果。
我是参考下面的链接做的。作为参考,css 使用 tailwind。
https://react-hook-form.com/advanced-usage#SmartFormComponent
代码:
// Form.tsx
import { Children, createElement, FormHTMLAttributes, ReactElement } from "react";
import { FormProvider, SubmitHandler, useForm, UseFormProps } from "react-hook-form";
interface FormProps<T> extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
form: UseFormProps<T>;
children: ReactElement | ReactElement[];
onSubmit: SubmitHandler<T>;
}
export default function Form<T>({ children, onSubmit, form, ...rest }: FormProps<T>): JSX.Element {
const methods = useForm<T>(form);
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)} {...rest}>
{Children.map(children, (child) => {
return child.props.name
? createElement<T>(child.type, {
...{
key: child.props.name,
...methods.register,
...child.props
}
})
: child;
})}
</form>
</FormProvider>
);
}
Run Code Online (Sandbox Code Playgroud)
// Input.tsx
import { ExclamationCircleIcon } from "@heroicons/react/solid";
import { InputHTMLAttributes } from "react";
import { useFormContext } from "react-hook-form";
import { classNames } from "../../utils/classNames";
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "id" | "className"> {
name: string;
label?: string;
}
export default function Input({ name, label, ...rest }: InputProps): JSX.Element {
const methods = useFormContext();
return (
<>
<div>
<div>
{label && (
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
{label}
</label>
)}
<div className="mt-1 relative">
<input
id={name}
{...methods.register(name)}
{...rest}
className={classNames(
methods.formState.errors[name]
? "border-red-300 text-red-900 placeholder-red-300 focus:ring-red-500 focus:border-red-500"
: "border-gray-300 placeholder-gray-400 focus:ring-indigo-500 focus:border-indigo-500",
"appearance-none block w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none sm:text-sm"
)}
/>
{methods.formState.errors[name] && (
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<ExclamationCircleIcon className="h-5 w-5 text-red-500" aria-hidden="true" />
</div>
)}
</div>
</div>
{methods.formState.errors[name] && (
<p className="mt-1 text-sm text-red-600">{methods.formState.errors[name].message}</p>
)}
</div>
</>
);
}
Run Code Online (Sandbox Code Playgroud)
// index.tsx
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { Form, Input } from "../form";
interface FormFields {
email: string;
password: string;
}
const schema = yup.object().shape({
email: yup.string().required("Email is required.").email("Email format is incorrect."),
password: yup
.string()
.required("Password is required.")
.matches(
/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!@#$%^&*])[A-Za-z0-9!@#$%^&*]{8,128}$/,
"Password format is incorrect."
)
});
export default function SignInForm(): JSX.Element {
const onSubmit = async (data: FormFields) => {
console.log(data);
};
return (
<Form<FormFields>
onSubmit={onSubmit}
form={{ resolver: yupResolver(schema), reValidateMode: "onChange" }}
className="space-y-6"
>
<Input name="email" type="email" label="Email address" />
<Input name="password" type="password" label="Password" />
<div>
<button type="submit" className="w-full flex justify-center py-2 px-4 btn btn-indigo">
Sign in
</button>
</div>
</Form>
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2300 次 |
| 最近记录: |