在组件中使用 react-hook-form 来传递动态文本字段的道具
react-hook-form use in component to pass props for dynamic text fields
原题
我有以下组件
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@ebrookes.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@ebrookes.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 上吗?
此外,如果我控制台记录数据,我会得到这个
在您上次更新您的问题后,我制作了一个可用的 CodeSandbox。您忘记设置 <input />
的名称属性,因此 RHF 没有机会访问表单字段。您在这里也不需要 useState
,因为您可以在 handleSubmit
.
的回调中访问表单数据
您还可以通过使用 name
属性作为 register
调用的第一个参数来简化您的界面。 register
的传播也将 return a 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@ebrookes.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>
);
}
);
原题
我有以下组件
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@ebrookes.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@ebrookes.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 上吗?
此外,如果我控制台记录数据,我会得到这个
在您上次更新您的问题后,我制作了一个可用的 CodeSandbox。您忘记设置 <input />
的名称属性,因此 RHF 没有机会访问表单字段。您在这里也不需要 useState
,因为您可以在 handleSubmit
.
您还可以通过使用 name
属性作为 register
调用的第一个参数来简化您的界面。 register
的传播也将 return a 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@ebrookes.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>
);
}
);