如何覆盖 useForm 中的 defaultValues 并维护 isDirty 函数?

How do I override the defaultValues in useForm and maintain the isDirty function?

我有一种情况需要调用我的数据库来获取一些默认值。但万一数据不存在,我会在 useForm 中设置一些默认值。基本上,这意味着如果我无法从数据库中获取默认值,则在 useForm 中声明的 defaultValues 是一个后备值。

据我了解,根据 documentation 关于 useForm

The defaultValues for inputs are used as the initial value when a component is first rendered, before a user interacts with it.

或者基本上,useForm 是加载页面时首先定义的内容之一。

因此,除非我可以在 useForm 加载之前调用我的数据库 ,否则我对此有点卡住了。

我读到每个 Controller 字段都可以有一个叫做 defaultValue 的东西,这听起来像是解决方案,但文档提到了一个警告

If both defaultValue and defaultValues are set, the value from defaultValues will be used.

我考虑过setValues,但我想使用isDirty函数,它允许字段验证和用于检查表单是否脏的值基于useForm defaultValues。因此,如果我要使用 setValues,表单将被声明为脏的,这是我不想要的。



TL;DR 这就是我想要的:

这是我的初始值(回退值,结果A)。

const { formState: { isDirty }, } = useForm(
        {defaultValues:{
            userID: "",
            userName: "",
            userClass: "administrator",
        }}
    );

我想做的是进行数据库调用并替换数据,这样如果调用成功,它现在看起来像这样(结果 B)(如果失败,它将保持结果 A) .

const { formState: { isDirty }, } = useForm(
        {defaultValues:{
            userID: "1",
            userName: "user",
            userClass: "administrator",
        }}
    );

请注意,数据库调用将仅替换 userIDuserName 默认值,将保留 userClass 的默认值。

所以,流程是这样的:

案例 1:渲染表单 -> 结果 A -> 数据库调用 -> 成功 -> 结果 B

案例 2:渲染表单 -> 结果 A -> 数据库调用 -> fail/no 数据 -> 结果 A

因此,除非我实际键入的输入与任一结果的默认值不同,否则情况 1 和情况 2 在我检查时都应该 return isDirty==false .

对于 react-hook-form@7.22.0 和更高版本

我想你想在这里结合使用 resetuseEffect 来在你的数据库调用完成时触发它。您还可以将一些配置设置为 reset 的第二个参数,例如在您的案例中影响 isDirty 状态。

尽管您的答案有效,但无需在此处使用 getValues,因为 reset 只会覆盖您传递给 reset 的字段。您的链接答案适用于旧版本的 RHF,这是必要的。

此外,如果您不在运行时动态添加字段,那么您可以将从数据库调用中获得的整个对象传递给 reset 并将 shouldUnregister 设置为 true 在你的 useForm 配置中。这样,您的 result 对象中没有相应表单字段的道具将被忽略。

export default function Form() {
  const { register, handleSubmit, reset, formState } = useForm({
    defaultValues: {
      userID: "",
      userName: "",
      userClass: "administrator"
    },
    shouldUnregister: true
  });

  console.log(formState.isDirty);

  const onSubmit = (data) => {
    console.log(data);
  };

  const onReset = async () => {
    const result = await Promise.resolve({
      userID: "123",
      userName: "Brian Wilson",
      otherField: "bla"
    });

    reset(result);
  };

  useEffect(() => {
    onReset();
  }, []);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>User ID</label>
      <input type="text" {...register("userID")} />

      <label>User Name</label>
      <input type="text" {...register("userName")} />

      <label>User Class</label>
      <input type="text" {...register("userClass")} />

      <input type="submit" />
    </form>
  );
}

这是一个演示上述解释的沙盒:

旧版本

只需通过 getValues 将您的 defaultValues 或字段值与数据库调用的结果合并。

export default function Form() {
  const {
    register,
    handleSubmit,
    reset,
    formState,
    getValues,
    control
  } = useForm({
    defaultValues: {
      userID: "",
      userName: "",
      userClass: "administrator"
    },
    shouldUnregister: true
  });

  console.log(formState.isDirty);

  const onSubmit = (data, e) => {
    console.log(data);
  };

  const onReset = async () => {
    const result = await delay();

    reset({ ...getValues(), ...result });
  };

  useEffect(() => {
    onReset();
  }, []);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>User ID</label>
      <input type="text" {...register("userID")} />

      <label>User Name</label>
      <input type="text" {...register("userName")} />

      <label>User Class</label>
      <Controller
        name="userClass"
        control={control}
        render={({ field }) => <input type="text" {...field} />}
      />

      <input type="submit" />
    </form>
  );
}

我进一步用谷歌搜索了 @knoefel's original answer, and I came across this

遇到的问题

因此,我想出的解决方案是结合@knoefel 的答案和 link 中的答案:


useEffect(async () => {

    let dataArray={};

    let result= fetch('my-db-call');
    if(result) {
       dataArray['userID']=result.userID
       dataArray['userName']=result.userName
    }

    reset({...getValues(), ...dataArray})
  }, [])

显然,reset 函数将首先使用 ...getValues() 设置值,即结果 A,之后的任何后续数据仅在存在时才会替换先前设置的值。 (例如,如果我的 dataArray 对象缺少 userID 键,它 将不会用新默认值替换 userID 默认值。)。

只有getValuesdataArray都设置好后才会重置为默认值。

据我所知,这或多或少符合我的需要,应该会给我结果 B。