簡體   English   中英

維護 useFieldArray react-hook-form 的狀態

[英]Maintain state of useFieldArray react-hook-form

我使用react-hook-form構建了一個多步表單,並使用 useFieldArray 構建了一個動態字段數組。

文檔: useFieldArray 文檔

這是完整的工作代碼鏈接: React Multi-step form with useFieldArray

在第二步中,當我使用添加狗按鈕添加新字段時,一切正常,使用小狀態機將步驟的新數據保存到本地存儲。

在此處輸入圖片說明

但是當我單擊上一個按鈕時,添加的字段消失了,而數據仍在本地存儲中。

第二步的代碼:

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) =>

每當單擊上一個按鈕時,字段數組都會重置為默認值。

在此處輸入圖片說明

當我們回到上一步時,除了第 2 步之外,表格的所有其余步驟都將被保存。

當我單擊上一個按鈕時,如何保存第二步中的字段。

這里有兩個問題:

  • 當您單擊“上一步”按鈕時,您不會在“第 2 步”中更新您的狀態。 所以你必須將當前的表單數據傳遞給你的狀態機。 此外,當您想要進行上一步時,您現在也沒有對“第 2 步”進行表單驗證。 要添加對驗證的支持,您應該從<form />元素中移動handleSubmit並將其傳遞給您的兩個<button />元素。 這樣您就可以擺脫 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>

如果您想在<form />元素中保留handleSubmit ,您應該使用 watch 並將數據傳遞到您的狀態機,然后再導航回上一步。

const test = watch("test");

const onPrevious = (data) => {
  actions.updateAction({ test });

  navigate("/");
};
  • 當您在步驟更改時重新初始化每個步驟組件時,您必須將當前的defaultValues useForm給每個步驟的useForm 對於“第 2 步”,它看起來像這樣:
const {
  register,
  control,
  handleSubmit,
  watch,
  formState: { errors }
} = useForm({
  defaultValues: {
    test: state.test ?? [
      { nameOfDog: "Bill", ageOfDog: "2", sizeOfDog: "small" }
    ]
  }
});

需要更改的重要一點是,當您在useForm配置中為您的字段傳遞defaultValues時,您應該將其從<Controller />組件中刪除。 我為“第 1 步”做的,所以你有一個例子。

編輯確定的月亮-j8b7b

它很長,但也許我們可以弄清楚。

使用是正確的,我認為問題在於您沒有檢查狀態並且每次都打印默認值

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM