[英]Maintain state of useFieldArray react-hook-form
I built a multistep form using react-hook-form with a dynamic fields array using useFieldArray.我使用react-hook-form构建了一个多步表单,并使用 useFieldArray 构建了一个动态字段数组。
Documentation: useFieldArray documentation文档: useFieldArray 文档
Here is the full working code link: React Multi-step form with useFieldArray这是完整的工作代码链接: React Multi-step form with useFieldArray
In the 2nd step when I add new fields using add a dog button, everything works fine, the new data of step is saved to localstorage using little state machine .在第二步中,当我使用添加狗按钮添加新字段时,一切正常,使用小状态机将步骤的新数据保存到本地存储。
But when I click the previous button, the added fields disappear whereas data is still in localstorage.但是当我单击上一个按钮时,添加的字段消失了,而数据仍在本地存储中。
code for 2nd step:第二步的代码:
import { useForm, useFieldArray } from "react-hook-form";
import { useStateMachine } from "little-state-machine";
import updateAction from "./updateAction";
import { useNavigate } from "react-router-dom";
function Step2(props) {
const {
register,
control,
handleSubmit,
watch,
formState: { errors },
} = useForm({
defaultValues: {
test: [{ nameOfDog: "Bill", ageOfDog: "2", sizeOfDog: "small" }],
},
});
const { fields, append, remove } = useFieldArray({
control,
shouldUnregister: true,
name: "test",
});
const elements = watch("test");
console.log(elements, fields);
const { actions, state } = useStateMachine({ updateAction });
const navigate = useNavigate();
const onSubmit = (data) => {
// console.log(fields);
actions.updateAction(data);
navigate("/step3");
};
let dta;
if (state.date2) {
dta = new Date(state.date2);
} else {
dta = new Date();
dta.setDate(dta.getDate() + 1);
}
return (
<form className="form" onSubmit={handleSubmit(onSubmit)}>
<div className="stepn stepn-active" data-step="1">
{fields.map((item, index) => {
return (
<div className="row" key={item.id}>
<div className="col">
<label htmlFor="nameOfDog">Name:</label>
<input
id="nameOfDog"
{...register(`test.${index}.nameOfDog`, {
required: true,
})}
defaultValue={item.nameOfDog}
/>
{errors.nameOfDog && (
<span>This field is required</span>
)}
</div>
<div className="col">
<label htmlFor="ageOfDog">Age:</label>
<input
id="ageOfDog"
type="number"
{...register(`test.${index}.ageOfDog`, {
required: true,
})}
defaultValue={item.ageOfDog}
/>
{errors.ageOfDog && (
<span>This field is required</span>
)}
</div>
<div className="col">
<label htmlFor="sizeOfDog">Size in Lbs:</label>
<select
id="sizeOfDog"
{...register(`test.${index}.sizeOfDog`, {
required: true,
})}
defaultValue={item.sizeOfDog || ""}
>
<option value="small">Small (40)</option>
<option value="large">Large (40+)</option>
</select>
{errors.sizeOfDog && (
<span>Please Select an option</span>
)}
</div>
<div className="col">
<button
onClick={(e) => {
e.preventDefault();
remove(index);
}}
style={{ padding: "26px 62px" }}
>
Delete
</button>
</div>
</div>
);
})}
<div className="row">
<div className="col">
<button
onClick={(e) => {
e.preventDefault();
append({
nameOfDog: "Bill2",
ageOfDog: "5",
sizeOfDog: "large",
});
}}
>
Add a Dog
</button>
</div>
</div>
</div>
{/* <input type="submit" /> */}
<div className="row">
<button className="prev" onClick={() => navigate("/")}>
Previous
</button>
<button className="next">Next</button>
</div>
</form>
);
}
export default Step2;
{fields.map((item, index) =>
whenever the previous button is clicked, fields array resets to default.每当单击上一个按钮时,字段数组都会重置为默认值。
All the remaining steps of the form except 2nd step is being saved when we go back to previous step.当我们回到上一步时,除了第 2 步之外,表格的所有其余步骤都将被保存。
How do i keep the fields in the 2nd step saved when I click the previous button.当我单击上一个按钮时,如何保存第二步中的字段。
There are two problems here:这里有两个问题:
handleSubmit
from the <form />
element and instead pass it to your two <button />
elements.<form />
元素中移动handleSubmit
并将其传递给您的两个<button />
元素。 This way you can get rid of the watch call as you have the current form data inside the handleSubmit callback.const onPrevious = (data) => {
actions.updateAction(data);
navigate("/");
};
const onNext = (data) => {
actions.updateAction(data);
navigate("/step3");
};
<div className="row">
<button className="prev" onClick={handleSubmit(onPrevious)}>
Previous
</button>
<button className="next" onClick={handleSubmit(onNext)}>
Next
</button>
</div>
If you want to keep handleSubmit
in the <form />
element, you should use watch and pass the data to your state machine before you navigate back to the previous step.如果您想在
<form />
元素中保留handleSubmit
,您应该使用 watch 并将数据传递到您的状态机,然后再导航回上一步。
const test = watch("test");
const onPrevious = (data) => {
actions.updateAction({ test });
navigate("/");
};
defaultValues
to useForm
for each step.defaultValues
useForm
给每个步骤的useForm
。 For "Step 2" it would look like this:const {
register,
control,
handleSubmit,
watch,
formState: { errors }
} = useForm({
defaultValues: {
test: state.test ?? [
{ nameOfDog: "Bill", ageOfDog: "2", sizeOfDog: "small" }
]
}
});
The important thing to change is, that when you pass the defaultValues
for your fields within the useForm
config, you should remove it from the <Controller />
components.需要更改的重要一点是,当您在
useForm
配置中为您的字段传递defaultValues
时,您应该将其从<Controller />
组件中删除。 I made it for "Step 1", so you have an example there.我为“第 1 步”做的,所以你有一个例子。
It's very long but maybe we can figure it out.它很长,但也许我们可以弄清楚。
The use is correct, the problem in my opinion is that you're not checking the state and just printing the default values everytime使用是正确的,我认为问题在于您没有检查状态并且每次都打印默认值
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.