react-hook-form 在组件中使用以传递动态文本字段的道具
Posted
技术标签:
【中文标题】react-hook-form 在组件中使用以传递动态文本字段的道具【英文标题】:react-hook-form use in component to pass props for dynamic text fields 【发布时间】:2022-01-21 16:31:58 【问题描述】:原始问题
我有以下组件
import React from 'react';
import PropTypes from 'prop-types';
import useForm from 'react-hook-form';
export default function FormField( type, name, formRegister, errorMsg, state )
const methods = useForm();
const register = methods;
return (
<>
<div>
<label htmlFor=name className="block text-sm font-medium text-gray-900">
Password
</label>
<div className="mt-1">
<input
type=type
name=name
...register( formRegister , required: errorMsg )
className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
onChange=(event) => state(event.target.value)
/>
</div>
</div>
</>
);
FormField.PropTypes =
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
formRegister: PropTypes.string.isRequired,
errorMsg: PropTypes.string.isRequired,
state: PropTypes.string.isRequired
;
FormField.defaultProps =
type: 'text',
name: 'text',
formRegister: 'text',
errorMsg: 'text is required',
state: 'setName'
;
我对这个组件的目标是创建一个动态字段组件,以便我可以执行以下操作
<FormField
type="password"
name="password"
formRegister="password"
errorMsg="Password is required"
state="setPassword"
/>
但是,我在传递 react-form-hooks ...register
时遇到问题
我得到以下信息
TypeError: path.split is not a function
任何帮助都会很棒,干杯。
原始编辑
感谢 knoefel,表单现在可以正常工作了,但是,问题出在这里,错误消息现在没有显示。
所以在我的组件中,我拥有传递错误所需的一切,但是它们没有显示,调试这个我发现当我这样做时
<FormField
...register(email, required: 'email is required' )
type="email"
label="Email"
name="email"
errorMsg="Email is required"
placeholder="john.doe@e***es.dev"
/>
现在显示错误,那么给出了什么?我已经在组件中有这个了?
更新问题 #2
我现在有以下组件
import React from 'react';
import PropTypes from 'prop-types';
const FormField = React.forwardRef(
( type, name, label, required, placeholder, ...props , ref) =>
return (
<div>
<label htmlFor=name className="block text-sm font-medium text-gray-900">
label
<span className="text-red-500 font-bold text-lg">required && '*'</span>
</label>
<div className="mt-1">
<input
...props
name=name
ref=ref
type=type
id=name
className=['field', `field--$type`].join(' ')
placeholder=placeholder
/>
</div>
</div>
);
);
export default FormField;
FormField.propTypes =
type: PropTypes.oneOf(['text', 'email', 'password', 'file', 'checkbox']),
register: PropTypes.func,
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
placeholder: PropTypes.string
;
FormField.defaultProps =
type: 'text',
name: 'text',
label: 'Label',
placeholder: ''
;
现在是下一页
import Head from 'next/head';
import Link from 'next/link';
import Image from 'next/image';
import Background from '../../../public/images/option1.png';
import Router from 'next/router';
import signIn from 'next-auth/client';
import useForm, FormProvider from 'react-hook-form';
// components
import ErrorsPopup from '../../components/ErrorsPopup';
import FormField from '../../components/Forms/FormField';
import Button from '../../components/Button';
export default function Login()
const methods = useForm();
const handleSubmit, register = methods;
const onSubmit = async (data) =>
await signIn('credentials',
redirect: false,
data
);
Router.push('/dashboard');
;
return (
<>
<Head>
<title>Ellis Development - Login</title>
</Head>
<div className="relative">
<div className="md:flex">
/* Image */
<div className="flex items-center justify-center bg-blue-700 h-screen lg:w-96">
<Image src=Background width=350 height=350 layout="fixed" />
</div>
/* Contact form */
<div className="flex flex-col justify-center px-6 sm:px-10 w-full">
<h1 className="text-4xl font-extrabold text-grey-800">Login</h1>
/* errors */
<FormProvider ...methods>
<ErrorsPopup />
</FormProvider>
<form
onSubmit=handleSubmit(onSubmit)
className="mt-6 flex flex-col gap-y-6 sm:gap-x-8">
/* email field */
<FormField
...register('email',
required: 'Email is required',
pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]2,$/i
)
type="email"
label="Email"
placeholder="john.doe@e***es.dev"
required
/>
/* password field */
<FormField
...register('password',
required: 'Password is required'
)
type="password"
label="Password"
placeholder="*******"
required
/>
<div className="flex items-center justify-between sm:col-span-2">
<div>
<Button type="submit" label="Login" icon="SaveIcon" />
</div>
<div>
<Link href="/dashboard/auth/register">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2 mr-4">
Register
</a>
</Link>
<Link href="/dashboard/auth/forgot">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2">
Forgot your password?
</a>
</Link>
</div>
</div>
</form>
</div>
</div>
</div>
</>
);
现在的问题是表单仍然没有提交。
任何帮助都会很棒,干杯。
编辑#2
这是我提交表单时得到的,还添加了console.log(formState.errors)
此外,当我填写表格时,我没有收到任何错误,那么问题是否可能出现在 onSubmit 上?。
另外,如果我控制台记录数据,我会得到这个
【问题讨论】:
【参考方案1】:在您上次更新您的问题后,我制作了一个有效的 CodeSandbox。您忘记设置 <input />
的名称属性,因此 RHF 没有机会访问表单字段。这里也不需要useState
,在handleSubmit
的回调中访问表单数据即可。
您还可以通过使用name
属性作为register
调用的第一个参数来简化您的界面。 register
的传播还将 return 一个 name
属性设置为您传递给 register
的第一个参数的名称。
export default function Login()
const methods = useForm();
const handleSubmit, register = methods;
const onSubmit = async (data) =>
console.log(data);
;
return (
<>
<Head>
<title>Ellis Development - Login</title>
</Head>
<div className="relative">
<div className="md:flex">
/* Image */
<div className="flex items-center justify-center bg-blue-700 h-screen lg:w-96"></div>
/* Contact form */
<div className="flex flex-col justify-center px-6 sm:px-10 w-full">
<h1 className="text-4xl font-extrabold text-grey-800">Login</h1>
<FormProvider ...methods>/* errors */</FormProvider>
<form
onSubmit=handleSubmit(onSubmit)
className="mt-6 flex flex-col gap-y-6 sm:gap-x-8"
>
/* email field */
<FormField
...register("email",
required: "Email is required",
pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]2,$/i
)
type="email"
label="Email"
placeholder="john.doe@e***es.dev"
required
/>
/* password field */
<FormField
...register("password",
required: "Email is required"
)
type="password"
label="Password"
placeholder="*******"
required
/>
<div className="flex items-center justify-between sm:col-span-2">
<div>
<input type="submit" label="Login" />
</div>
<div>
<Link href="/dashboard/auth/register">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2 mr-4">
Register
</a>
</Link>
<Link href="/dashboard/auth/forgot">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2">
Forgot your password?
</a>
</Link>
</div>
</div>
</form>
</div>
</div>
</div>
</>
);
const FormField = forwardRef(
( type, name, label, required, placeholder, ...props , ref) =>
return (
<div>
<label
htmlFor=name
className="block text-sm font-medium text-gray-900"
>
label
<span className="text-red-500 font-bold text-lg">
required && "*"
</span>
</label>
<div className="mt-1">
<input
...props
name=name
ref=ref
type=type
id=name
className=["field", `field--$type`].join(" ")
placeholder=placeholder
/>
</div>
</div>
);
);
【讨论】:
啊,所以我不小心设置了两个对象而不是一个? 是的。register
的签名要求第一个参数是字符串,第二个参数是规则对象。查看文档here 了解更多信息。您还应该将errorMsg
直接设置为required
,而不是通过对象。否则您需要将其重命名为 message
在同一部分的文档中还有一个示例。
你能提供一个errorMsg原因的例子吗,因为在将字段更改为新组件后,错误消息不再弹出。
来自文档 for required:一个布尔值,如果为真,则表示输入必须具有值才能提交表单。您可以分配一个字符串以在错误对象中返回错误消息。
示例:以上是关于react-hook-form 在组件中使用以传递动态文本字段的道具的主要内容,如果未能解决你的问题,请参考以下文章
在 Angular 8 中,如何将一个组件传递给另一个组件的输入,然后在路由器模块中强制使用它
如何将 MUI Select 与 react-hook-form 一起使用?