在组件中使用 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>
    );
  }
);