如何让 react-hook-form 在一个页面中处理多个表单?

73

我在我的项目中使用react-hook-form,我有2个完全独立的表单,但是当我提交其中一个表单并且另一个表单中的某些字段是必填项时,我无法提交当前表单,请查看演示,并尝试提交其中一个表单,这些表单应该彼此独立工作,但它们似乎相互依赖。

4个回答

117

您正在为两个表单使用相同的钩子实例。您需要使用不同的名称进行重用。

import React from "react";
import ReactDOM from "react-dom";
import { useForm } from "react-hook-form";

import "./styles.css";

function App() {
  const {
    register,
    formState: { errors },
    handleSubmit,
  } = useForm({
    mode: "onBlur",
  });

  const {
    register: register2,
    formState: { errors: errors2 },
    handleSubmit: handleSubmit2,
  } = useForm({
    mode: "onBlur",
  });

  const onSubmit = (data) => {
    alert(JSON.stringify(data));
  };

  const onSubmitEmail = (data) => {
    alert(JSON.stringify(data));
  };

  return (
    <div className="App">
      <form key={1} onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label htmlFor="firstName">First Name</label>
          <input
            name="firstName"
            placeholder="bill"
            ref={register({ required: true })}
          />
          {errors.firstName && <p>This is required</p>}
        </div>

        <div>
          <label htmlFor="lastName">Last Name</label>
          <input
            name="lastName"
            placeholder="luo"
            ref={register({ required: true })}
          />
          {errors.lastName && <p>This is required</p>}
        </div>
        <input type="submit" />
      </form>

      <form key={2} onSubmit={handleSubmit2(onSubmitEmail)}>
        <div>
          <label htmlFor="email" placeholder="bluebill1049@hotmail.com">
            Email
          </label>
          <input name="email" ref={register2({ required: true })} />
          {errors2.email && <p>This is required</p>}
        </div>
        <input type="submit" />
      </form>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

17
非常棒的答案,问候也非常友善。 - Bill
1
如果您正在使用早于V7的react-hook-form,请查看Sibiraj的编辑历史。 - Faizaan Khan
3
你注意到了吗?评论的那个人@bill是React Use Form的创作者。 - Eddy sapata
2
@Eddysapata 哈哈,我没有,我以为是提问的人。Bill在使用这个包时取得了很好的成功。这确实是一件了不起的工作。 - Faizaan Khan
3
在表单标签内,我们需要这些key={1}key={2}吗? - uberrebu

11

快速更新Faizaan的答案:在我的情况下,应该使用formStateerrors一起使用,而不是单独使用。因此,属性应该导入为:

const { formState: { errors } } = useForm();
const { formState: { errors: errors2 } } = useForm();

名字可能会让人困惑,但这是我得出的解决方案。


从版本7开始。 - Faizaan Khan
10
在页面上动态创建多个表单是否可行?此处硬编码了2个表单,能否创建一个React Hook Form列表并在页面上动态渲染? - Mark Redman
我一直在尝试做这件事,@MarkRedman,但我还没有成功。钩子有规则,使得它不那么简单。当然,我只是几个月前开始使用React,所以其他人可能更懂。 - benJephunneh
2
@benJephunneh 我记不得我是怎么做到的了,当时也是刚接触React.js... 在React中,只需要考虑组件,所以创建一个带有1个表单的新组件,然后渲染多个组件即可。 - Mark Redman

2
作为一种(稍微)更可扩展的方法,您可以将上下文钩子包装在一个函数中,并使用它来进行重复注册:
export default function Page() {

    // Wrap the hook in a function
    const registerForm = () => {
        const { register, formState, handleSubmit } = useForm();
        return { register, formState, handleSubmit };
    }

    // Register multiple forms
    const forms = {
        email: registerForm(),
        delivery: registerForm(),
        payment: registerForm(),
    }

....

只需从每个 registerForm 常量中使用 props:

// Form 1
<form onSubmit={forms.email.handleSubmit(onSubmit)}>
  <Text
    id="email"
    register={forms.email.register}
    formState={forms.email.formState}
    validation={{required: 'Email address is required'}}
  />
  <Submit />
</form>

// Form 2
<form onSubmit={forms.delivery.handleSubmit(onSubmit)}>
  <Text
    id="email"
    register={forms.delivery.register}
    formState={forms.delivery.formState}
    validation={{required: 'Delievery address is required'}}
  />
  <Submit />
</form>

... etc.

0

如果有人正在使用useForm与其他库(如Material UI)并且有两个表单,则可以使用:

const { control, handleSubmit } = useForm({
resolver: yupResolver(schema), })

const { control: control2, handleSubmit: handleSubmitReset } = useForm({
    resolver: yupResolver(schema2),
  });


  const onSubmit = async (data) => {
    console.log(data);
  };

 const onSubmitResend = async (data) => {
        console.log(data);
      };

表单的样式如下:

表单-1

<form key={1} onSubmit={handleSubmitReset(onSubmitResend)}>
          <FormLabel
            component="legend"
            color="secondary"
            sx={{ color: "#fff", pt: 2 }}
          >
            Email:
          </FormLabel>
          <Controller
            defaultValue=""
            name="email"
            control={control2}
            render={({
              field: { onChange, value },
              fieldState: { error },
            }) => (
              <TextField
                helperText={error ? error.message : null}
                error={!!error}
                value={value}
                onChange={onChange}
                id="outlined-basic"
                placeholder="Enter Email address"
                variant="outlined"
                fullWidth
                color="secondary"
                InputProps={{
                  style: {
                    color: "#fff",
                    border: "1px solid #fff",
                    borderRadius: "32px",
                    marginTop: "16px",
                  },
                }}
              />
            )}
          />

          >
            <Button
              fullWidth
              color="secondary"
              type="submit">
               Submit
            </Button>
        </form>

表格-2

 <form key={2} onSubmit={handleSubmit(onSubmit)}>
          <FormLabel
            component="legend"
            color="secondary"
            sx={{ color: "#fff", pt: 2 }}
          >
            Email:
          </FormLabel>
          <Controller
            defaultValue=""
            name="email"
            control={control}
            render={({
              field: { onChange, value },
              fieldState: { error },
            }) => (
              <TextField
                helperText={error ? error.message : null}
                error={!!error}
                value={value}
                onChange={onChange}
                id="outlined-basic"
                placeholder="Enter Email address"
                variant="outlined"
                fullWidth
                color="secondary"
                InputProps={{
                  style: {
                    color: "#fff",
                    border: "1px solid #fff",
                    borderRadius: "32px",
                    marginTop: "16px",
                  },
                }}
              />
            )}
          />

          >
            <Button
              fullWidth
              color="secondary"
              type="submit">
               Submit
            </Button>
        </form>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接