【问题标题】:How do I override the defaultValues in useForm and maintain the isDirty function?如何覆盖 useForm 中的 defaultValues 并维护 isDirty 函数?
【发布时间】:2022-01-06 10:40:16
【问题描述】:

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

据我了解,根据documentationuseForm

当一个组件第一次被渲染时,在用户与之交互之前,输入的默认值被用作初始值。

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

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

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

如果同时设置了 defaultValue 和 defaultValues,将使用 defaultValues 中的值

我考虑过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",
        }}
    );

请注意,DB 调用将仅替换 userIDuserName 的默认值,userClass 的默认值将保持不变。

所以,流程是这样的:

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

案例 2:渲染表单 -> 结果 A -> 数据库调用 -> 失败/无数据 -> 结果 A

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

【问题讨论】:

    标签: reactjs react-hooks react-hook-form


    【解决方案1】:

    对于react-hook-form@7.22.0 及更新版本

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

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

    此外,如果您没有在运行时动态添加字段,那么您可以将您从 DB 调用中获得的整个对象传递给 reset,并在您的 useForm 配置中将 shouldUnregister 设置为 true。这样,您的 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>
      );
    }
    

    这里是一个沙盒,演示了上面的解释:

    对于旧版本

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

    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>
      );
    }
    

    【讨论】:

    • 这看起来可行。将不得不尝试一下。但是阅读文档时,会出现一个问题:它会覆盖所有defaultValues 结果还是我可以针对特定字段执行此操作?因为我需要为特定领域做这件事。我将在主帖中进一步澄清。
    • @Erik 请查看我的更新答案。您的回答有点误导,并且涵盖了 RHF 的旧版本。除此之外,使用getValues还有一个缺陷。
    • " reset 只会覆盖您传递给 reset 的字段" - 在我写下我的答案之前,我实际上尝试根据您的原始答案做一些类似于您所做的事情:仅在字段中解析我想重置。发生的事情是,除了我解析的字段之外的所有其他字段都变成了""。我所做的与我的答案相同,但减去了 getValues() 函数(所以它基本上是 reset({...dataArray}) )。 AFAIK,我应该专门使用 RHF 7.20.2,所以也许我错过了一些东西。
    • 感谢您的输入,我检查了它,只有在 react-hook-form@7.22.0 之后才有可能使用 reset,正如我在原始答案中所写的那样。我更新了我的答案,为这两种情况提供解决方案。尽管如此,我认为您可以在您的 useEffect 中省略对 result 的检查 - 检查我的答案或沙箱。
    【解决方案2】:

    我去进一步搜索了我在@knoefel's original answer 遇到的问题,我遇到了this

    因此,我提出的解决方案是结合@knoefel 的答案和链接中的答案:

    
    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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-09
      • 1970-01-01
      • 1970-01-01
      • 2015-10-02
      • 2018-01-10
      • 1970-01-01
      • 2021-12-12
      • 2011-07-21
      相关资源
      最近更新 更多