React Hook Form: 提交包含嵌套组件的表单或提取嵌套组件的字段以进行提交

25

我有一个表单,其中包含多个组件(每个组件都是函数式或类组件),其中包含多个输入字段或单选按钮。当我提交表单时,我要么希望提交嵌套在组件中的字段以及表单数据,要么我应该能够提取字段数据,然后再提交它们(不确定哪种方法最好以及为什么?)。我如何实现这个目标?

代码:

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

export default function TestComponent() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label htmlFor="name">Name</label>
      <input type="text" id="name" name="name" ref={register({ required: true, maxLength: 30 })} />
      {errors.name && errors.name.type === "required" && <span>This is required</span>}
      {errors.name && errors.name.type === "maxLength" && <span>Max length exceeded</span> }
      <NestedComponent1 />
      <NestedComponent2 />
      <input type="submit" />
    </form>
  );
}

function NestedComponent1() {
    return (
        <div>
            <input type="text" id="nested-name" name="nestedName" />
            <input type="text" id="nested-name2" name="nestedName2" />
            <input type="text" id="nested-name3" name="nestedName3" />
        </div>
    );
}

function NestedComponent2() {
    return (
        <div>
            <input type="text" id="nested-comp2-name" name="nestedcomp2Name" />
            <input type="text" id="nested-comp2-name2" name="nestedcomp2Name2" />
            <input type="text" id="nested-comp2-name3 name="nestedcomp2Name3" />
        </div>
    );
}
2个回答

23
您可以使用钩子useFormContext来避免将上下文作为prop传递https://react-hook-form.com/api/useformcontext。只需要使用FormProvider组件包装您的表单,以便在嵌套组件中使用useFormContext获取上下文即可。
export default function TestComponent() {
    const methods = useForm();
    const { register, handleSubmit, errors } = methods;
    const onSubmit = data => console.log(data);

    return (
    <FormProvider {...methods} > // pass all methods into the context
        <form onSubmit={handleSubmit(onSubmit)}>
        <label htmlFor="name">Name</label>
        <input type="text" id="name" name="name" ref={register({ required: true, maxLength: 30 })} />
        {errors.name && errors.name.type === "required" && <span>This is required</span>}
        {errors.name && errors.name.type === "maxLength" && <span>Max length exceeded</span> }
        <NestedComponent1 />
        <input type="submit" />
        </form>
    </FormProvider>
    );
}

function NestedComponent1() {
    const { register } = useFormContext(); // retrieve all hook methods
    
    return (
        <div>
            <input {...register("nestedName")} type="text" id="nested-name" name="nestedName"  />
            <input {...register("nestedName2")} type="text" id="nested-name2" name="nestedName2" />
            <input {...register("nestedName3")} type="text" id="nested-name3" name="nestedName3" />
        </div>
    );
}


1
你好 @Larissa,谢谢你的回答。它有效了。我正在使用你的方法,在主组件上使用Yup验证模式。当嵌套表单的一个字段无效时,Yup模式的错误消息不会被复制到嵌套组件中。你知道如何实现这一点吗? - Cassio Seffrin
谢谢,这对我也起作用了。 - Asmaa3107
你可以将错误作为prop传递给嵌套组件,这在我的情况下可行。 - Asmaa3107

4
为了从嵌套组件中提取数据,您可以在TestComponent中添加"useState"并将一个onChange函数传递给嵌套组件。
import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label htmlFor="name">A</label>
      <input
        type="text"
        id="name"
        name="name"
        ref={register({ required: true, maxLength: 30 })}
      />
      {errors.name && errors.name.type === "required" && (
        <span>This is required</span>
      )}
      {errors.name && errors.name.type === "maxLength" && (
        <span>Max length exceeded</span>
      )}
      <NestedComponent1 register={register} />
      <NestedComponent2 register={register} />
      <input type="submit" />
    </form>
  );
}

function NestedComponent1({register}) {
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <label htmlFor="nestedName">B</label>
      <input type="text" id="nested-name" name="nestedName" ref={register} />
      <label htmlFor="nesteNamename2">C</label>
      <input type="text" id="nested-name2" name="nestedName2" ref={register} />
      <label htmlFor="nestedName3">D</label>
      <input type="text" id="nested-name3" name="nestedName3" ref={register} />
    </div>
  );
}

function NestedComponent2({ register }) {
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <label htmlFor="nestedcomp2Name">E</label>
      <input
        type="text"
        id="nested-comp2-name"
        name="nestedcomp2Name"
        ref={register}
      />
      <label htmlFor="nestedcomp2Name2">F</label>
      <input
        type="text"
        id="nested-comp2-name2"
        name="nestedcomp2Name2"
        ref={register}
      />
      <label htmlFor="nestedcomp2Name3">G</label>
      <input
        type="text"
        id="nested-comp2-name3"
        name="nestedcomp2Name3"
        ref={register}
      />
    </div>
  );
}

我们不能通过 React-hook-form 做同样的事情吗?我的意思是,难道我们没有办法只使用它来收集所有嵌套字段数据吗?因为当我点击提交时,我希望 React Hook Form 读取字段数据。 - Ahmed
2
我改变了我的答案,请查看上面。你需要做的就是将register方法传递给子组件。同时请查看react-hook-form的官方文档:https://react-hook-form.com/advanced-usage/ - Yardie
https://react-hook-form.com/advanced-usage/ 这可能会有所帮助。 - nbpeth
1
这是唯一一个对我有效的解决方案。 - leyla azari

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