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。您忘记设置 &lt;input /&gt; 的名称属性,因此 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 一起使用?

VB.net 的异步组件

选择上的 forwardRef 不会使用 react-hook-form 保存选择的值

react-hook-form使用

react-hook-form yup 解析器,reactStrap 解决子组件错误的问题