简体   繁体   English

维护 useFieldArray react-hook-form 的状态

[英]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:这里有两个问题:

  • you don't update your state in "Step 2" when you click on the "Previous" button.当您单击“上一步”按钮时,您不会在“第 2 步”中更新您的状态。 So you have to pass the current form data to your state machine.所以你必须将当前的表单数据传递给你的状态机。 Additionally you also have no form validation for "Step 2" right now, when you want to go a previous step.此外,当您想要进行上一步时,您现在也没有对“第 2 步”进行表单验证。 To add support for validation you should move 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.这样您就可以摆脱 watch 调用,因为您在 handleSubmit 回调中有当前的表单数据。
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("/");
};
  • as you reinitialise each step component on a step change you have to pass the current defaultValues to useForm for each step.当您在步骤更改时重新初始化每个步骤组件时,您必须将当前的defaultValues useForm给每个步骤的useForm For "Step 2" it would look like this:对于“第 2 步”,它看起来像这样:
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 步”做的,所以你有一个例子。

编辑确定的月亮-j8b7b

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM