我正在尝试使用 React Hook Form 构建一种多步骤表单,但它不是经典的多步骤表单。就我而言,我需要在每次提交时保留在数据库中。
对我来说,这表明我应该将表单拆分为小表单,并单独验证每个表单。
这种方法的唯一问题(但并不简单)是,现在我遇到了一个步骤需要来自另一个步骤的数据的情况。由于每个单独的表单都有自己的
FormProvider
,因此我只能使用 useContext
来访问其对应上下文中的数据。我不想构建另一个上下文只是为了存储所有步骤的所有数据。
这是我目前拥有的结构的插图
interface IForm1 {
id?: number;
}
interface IForm2 {
name?: string;
}
const GenericForm = <T extends FieldValues, >(props: PropsWithChildren<T>) => {
const form = useForm<T>();
return <FormProvider {...form}>
<form>
{props.children}
</form>
</FormProvider>;
};
const MyForms = () => <>
<GenericForm<IForm1>>
<Component1 />
</GenericForm>
<GenericForm<IForm2>>
<Component1 />
</GenericForm>
</>;
现在我希望子组件能够从两个上下文访问数据,如下所示:
const Component1 = () => {
const { watch } = useFormContext<IForm1>();
const form2Context = useFormContext<IForm2>();
const id = watch('id');
const name = form2Context.watch('name');
return <div>
{id}
and
{name}
</div>;
};
这是行不通的,因为每个 FormProvider 都处于不同的级别,所以我想到做这样的事情:
const MyForms = () => <>
<FormProvider {...form1}>
<FormProvider {...form2}>
<GenericForm<IForm1>>
<Component1 />
</GenericForm>
<GenericForm<IForm2>>
<Component1 />
</GenericForm>
</FormProvider>
</>;
这也不起作用,最深的 FormProvider 似乎覆盖了所有父母。
有人遇到过这样的问题吗?有什么想法吗?
我正在研究的另一个想法是尝试向父级公开表单方法 -
watch
setValue
并以某种方式将它们注册到记录中。这样任何孩子都可以使用它们。问题是让这些方法保持同步真的很难。
更新
我找到了一种组合 useForm() 实例的方法
It is something like this:
const form1 = useForm();
const form2 = useForm();
<FormProvider {...{ ...form1, ...form2}}>
<form>Form 1</form>
<form>Form 2</form>
</FormProvider>
问题是,当我尝试使用
useFormContext
时,我可以看到上下文包含一个大对象,其中包含两种形式的所有属性,就好像它们只是简单地组合在一起一样。
我认为上下文会彼此分离,我可以做类似的事情:
const form1 = useFormContext<IForm1>();
这不起作用=/
我建议您使用州立图书馆。因为有时当表单开始变得复杂时,使用
React Context
来管理这些表单可能会很痛苦。
我用过的状态管理库是@legendapp/state。
它易于使用,并且在大多数情况下都具有高性能。
但是如果你想坚持使用 React 上下文;唯一可能的解决方案是使用一个表单提供程序,每个表单具有不同的对象。
状态对象就像这样:
{
form1: {data},
form2: {data},
form3: {data}
}
然后在每个子表单中,使用
useEffect
和 useWatch
更新上下文中的数据。
@Brian 有一个好主意,这是一个可以动态执行此操作的简单方法
首先你会有这个
<FormProvider {form1, form2}}>
<Form contextKey="form1">Form 1 </Form>
<Form contextKey="form1">Form 2 </Form>
</FormProvider>
// and then use your Form
const Form = ({contextKey, children}:{contextKey: string,children: any}) => {
const form = (useContext() as any)[contextKey];
// and now based on the contextKey you can get the right form.
return (
<form>
{children}
</form>
)
};
您必须使用
state
和 useEffect
来查看变化。
让我知道你的想法