具有全局状态的嵌套表单
Nested forms with global state
我正在构建一个大型表单应用程序。
问题是表单由许多嵌套表单组成。第一阶段/表格对所有用户都是相似的。然后,根据用户的输入,将显示不同的表单。这意味着每个表单都有自己的本地状态,并且在提交每个表单时,全局状态都会被更新。
为了清楚起见,请参阅下面的一小部分全局状态:
const [state, setState] = useState({
startForm {
email: "",
priority: "",
requestType: "",
dueDate: "",
},
designRequest: {
designType: "",
yellow: { client:"" , message: "" },
red: { change: "", parameter: "" }
}
}
);
const handleStartStepData = (startStepData) => { var startStep = {...state.startForm} state.startForm = startStepData setState({ startStep })
};
return ( <StartForm state={startStepState} onChange={handleStartStepData}/>
)
开始表格:
export const StartForm = (props) => {
const methods = useForm();
const [state, setState] = useState({
email: "",
priority: "",
requestType: "",
dueDate: "",
});
const onSubmit = (data) => {
const startFormState = data;
props.onChange(startFormState);
};
填写开始表单(电子邮件、优先级、请求类型和截止日期)后,屏幕上将显示不同的表单,具体取决于请求类型。因此,例如,如果用户选择了一个设计请求,他们将在黄色和红色请求之间进行选择。
我正在使用 React 表单挂钩以及 material UI 组件。我尝试为父级(全局表单)上的每个小表单设置一个句柄提交,但每个小表单都会覆盖全局状态而不是合并它。
我是 React 的新手,可以使用您的任何想法来更好地管理此应用程序中的状态。
正确的做法是使用 FormProvider 和 useFormContext。您所有的小表单都应嵌套在 FormProvider 中。
参见 codesandbox 上的示例 - https://codesandbox.io/s/react-hook-form-v7-form-context-forked-t02g0?file=/src/index.js:0-1602
文档 = https://react-hook-form.com/api/useformcontext
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { useForm, FormProvider, useFormContext } from "react-hook-form";
import "./styles.css";
export default function App() {
const methods = useForm();
const [formData, setFormData] = useState();
const onSubmit = (data) => setFormData(data);
console.log(methods.formState.errors);
return (
<>
<FormProvider {...methods}>
{" "}
{/* // pass all methods into the context */}
<form onSubmit={methods.handleSubmit(onSubmit)}>
<NestedNameEmailForm />
<NestedAddressForm />
<input type="submit" />
</form>
</FormProvider>
<p>DATA</p>
<pre style={{ color: "white" }}>{JSON.stringify(formData, null, 2)}</pre>
<p>ERRORS</p>
<pre style={{ color: "white" }}>
{JSON.stringify(Object.keys(methods.formState.errors), null, 2)}
</pre>
</>
);
}
function NestedNameEmailForm() {
const { register } = useFormContext(); // retrieve all hook methods
return (
<>
<input
{...register("first", {
required: true
})}
placeholder="First"
/>
<input
{...register("last", {
required: true
})}
placeholder="Last"
/>
<input
{...register("email", {
required: true
})}
placeholder="Email"
/>
</>
);
}
function NestedAddressForm() {
const { register } = useFormContext(); // retrieve all hook methods
return (
<>
<input
{...register("address_line_1", {
required: true
})}
placeholder="Address Line 1"
/>
<input {...register("address_line_2")} placeholder="Address Line 1" />
<input
{...register("city", {
required: true
})}
placeholder="City"
/>
<input
{...register("state", {
required: true
})}
placeholder="State"
/>
<input
{...register("zip", {
required: true
})}
placeholder="Zip"
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我正在构建一个大型表单应用程序。 问题是表单由许多嵌套表单组成。第一阶段/表格对所有用户都是相似的。然后,根据用户的输入,将显示不同的表单。这意味着每个表单都有自己的本地状态,并且在提交每个表单时,全局状态都会被更新。
为了清楚起见,请参阅下面的一小部分全局状态:
const [state, setState] = useState({
startForm {
email: "",
priority: "",
requestType: "",
dueDate: "",
},
designRequest: {
designType: "",
yellow: { client:"" , message: "" },
red: { change: "", parameter: "" }
}
}
);
const handleStartStepData = (startStepData) => { var startStep = {...state.startForm} state.startForm = startStepData setState({ startStep })
};
return ( <StartForm state={startStepState} onChange={handleStartStepData}/>
)
开始表格:
export const StartForm = (props) => {
const methods = useForm();
const [state, setState] = useState({
email: "",
priority: "",
requestType: "",
dueDate: "",
});
const onSubmit = (data) => {
const startFormState = data;
props.onChange(startFormState);
};
填写开始表单(电子邮件、优先级、请求类型和截止日期)后,屏幕上将显示不同的表单,具体取决于请求类型。因此,例如,如果用户选择了一个设计请求,他们将在黄色和红色请求之间进行选择。 我正在使用 React 表单挂钩以及 material UI 组件。我尝试为父级(全局表单)上的每个小表单设置一个句柄提交,但每个小表单都会覆盖全局状态而不是合并它。 我是 React 的新手,可以使用您的任何想法来更好地管理此应用程序中的状态。
正确的做法是使用 FormProvider 和 useFormContext。您所有的小表单都应嵌套在 FormProvider 中。
参见 codesandbox 上的示例 - https://codesandbox.io/s/react-hook-form-v7-form-context-forked-t02g0?file=/src/index.js:0-1602
文档 = https://react-hook-form.com/api/useformcontext
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { useForm, FormProvider, useFormContext } from "react-hook-form";
import "./styles.css";
export default function App() {
const methods = useForm();
const [formData, setFormData] = useState();
const onSubmit = (data) => setFormData(data);
console.log(methods.formState.errors);
return (
<>
<FormProvider {...methods}>
{" "}
{/* // pass all methods into the context */}
<form onSubmit={methods.handleSubmit(onSubmit)}>
<NestedNameEmailForm />
<NestedAddressForm />
<input type="submit" />
</form>
</FormProvider>
<p>DATA</p>
<pre style={{ color: "white" }}>{JSON.stringify(formData, null, 2)}</pre>
<p>ERRORS</p>
<pre style={{ color: "white" }}>
{JSON.stringify(Object.keys(methods.formState.errors), null, 2)}
</pre>
</>
);
}
function NestedNameEmailForm() {
const { register } = useFormContext(); // retrieve all hook methods
return (
<>
<input
{...register("first", {
required: true
})}
placeholder="First"
/>
<input
{...register("last", {
required: true
})}
placeholder="Last"
/>
<input
{...register("email", {
required: true
})}
placeholder="Email"
/>
</>
);
}
function NestedAddressForm() {
const { register } = useFormContext(); // retrieve all hook methods
return (
<>
<input
{...register("address_line_1", {
required: true
})}
placeholder="Address Line 1"
/>
<input {...register("address_line_2")} placeholder="Address Line 1" />
<input
{...register("city", {
required: true
})}
placeholder="City"
/>
<input
{...register("state", {
required: true
})}
placeholder="State"
/>
<input
{...register("zip", {
required: true
})}
placeholder="Zip"
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);