【问题标题】:Conditional validation with react hook form使用反应钩子形式进行条件验证
【发布时间】:2021-03-23 05:58:47
【问题描述】:

这是我的表格,也是CodeSanbox。目前我正在使用 react-hook-form
如您所见,表单有 3 个输入。在输入所有必填字段之前,应禁用提交按钮。 两个用例:

  1. 如果未选中“检查”:
    • 只有“id”应该被验证并且提交按钮应该被启用。 “first”和“last”名称不应成为表单数据的一部分
  2. 如果选中“检查”
    • 应验证所有字段
      只有在选中“检查”时才需要名字和姓氏。所以它没有被检查然后表单应该只验证“ID”字段。如果选中“检查”,则应验证所有字段。

我遇到的问题是,如果我输入 id,表单状态仍然是“无效”。表单需要输入名字和姓氏的值。
我将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    我已更新您的 CodeSanBox 代码,并在此处添加完整代码:

    import React, { useState, useEffect } from "react";
    import ReactDOM from "react-dom";
    import { useForm } from "react-hook-form";
    
    import "./index.css";
    
    function App() {
      const {
        register,
        handleSubmit,
        errors,
        formState,
        unregister,
        setValue,
        getValues,
        reset
      } = useForm({
        mode: "onBlur",
        reValidateMode: "onBlur",
        shouldUnregister: true
      });
      //console.log(formState.isValid);
      console.log(errors);
      const [disabled, setDisabled] = useState(true);
      const onSubmit = (data) => {
        alert(JSON.stringify(data));
      };
      useEffect(() => {
        // @ts-ignore
    
        if (disabled) {
          console.log("unregister");
          reset({ ...getValues(), firstName: undefined, lastName: undefined });
          unregister(["firstName", "lastName"]);
        } else {
          console.log("register");
          register("firstName", { required: true });
          register("lastName", { required: true });
        }
      }, [disabled]);
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          <label htmlFor="id">ID</label>
          <input
            name="id"
            placeholder="id"
            ref={register({ required: true, maxLength: 50 })}
          />
          {errors.id && <p>"ID is required"</p>}
          <fieldset disabled={disabled}>
            <legend>
              <input
                type="checkbox"
                name={"name"}
                ref={register}
                onClick={() => setDisabled(!disabled)}
              />
              <span>Check</span>
            </legend>
            <label htmlFor="firstName">First Name</label>
            <input
              name="firstName"
              placeholder="Bill"
              onChange={(e) => {
                console.log(e.target.value);
                setValue("firstName", e.target.value);
              }}
              ref={register({ required: !disabled })}
            />
            {errors.firstName && <p>"First name is required"</p>}
            <label htmlFor="lastName">Last Name</label>
            <input
              name="lastName"
              placeholder="Luo"
              onChange={(e) => setValue("lastName", e.target.value)}
              ref={register({ required: !disabled })}
            />
            {errors.lastName && <p>"Last name is required"</p>}
          </fieldset>
    
          <input type="submit" disabled={!formState.isValid} />
        </form>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    
    

    首先我发现您将disabled 状态设置为false,这应该是true 作为初始值,关于这个问题,我在disabled 状态时使用了resetgetValues 函数变化。

    EDIT让你更容易识别代码更改,我已经在 CodeSanBox 恢复了所有代码。

    【讨论】:

    • 在使用 Joi 或 Yup 等解析器进行验证时如何做同样的事情,有没有办法根据条件动态更改解析器验证?
    • @NabeelHussainShah 如果您使用 Yup,请查看 when 子句
    【解决方案2】:

    整个验证行为 (UX) 肯定会让事情变得更加困难,但是,您应该从库中利用一些东西,例如:

    • watch
    • validate
    • getValues
    import React from "react";
    import ReactDOM from "react-dom";
    import { useForm } from "react-hook-form";
    
    import "./index.css";
    
    function App() {
      const {
        register,
        handleSubmit,
        errors,
        formState: { isValid, touched },
        getValues,
        trigger,
        watch
      } = useForm({
        mode: "onBlur"
      });
      const onSubmit = (data) => {
        alert(JSON.stringify(data));
      };
      const validate = (value) => {
        if (getValues("name")) { // read the checkbox value
          return !!value;
        }
    
        return true;
      };
      const isChecked = watch("name"); // watch if the name is checked
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          <label htmlFor="id">ID</label>
          <input
            name="id"
            placeholder="id"
            ref={register({ required: true, maxLength: 50 })}
          />
          {errors.id && <p>"ID is required"</p>}
    
          <fieldset disabled={!isChecked}>
            <legend>
              <input
                type="checkbox"
                name={"name"}
                ref={register}
                onChange={() => trigger()} // you want update isValid due to state change, and also those extra two inputs become required
              />
              <span>Check</span>
            </legend>
            <label htmlFor="firstName">First Name</label>
            <input
              name="firstName"
              placeholder="Bill"
              ref={register({
                validate
              })}
            />
            // make sure input is touched before fire an error message to the user
            {errors.firstName && touched["firstName"] && (
              <p>"First name is required"</p>
            )}
            <label htmlFor="lastName">Last Name</label>
            <input
              name="lastName"
              placeholder="Luo"
              ref={register({
                validate
              })}
            />
            {errors.lastName && touched["lastName"] && (
              <p>"Last name is required"</p>
            )}
          </fieldset>
    
          <input type="submit" disabled={!isValid} />
        </form>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    CSB: https://codesandbox.io/s/react-hook-form-conditional-fields-forked-n0jig?file=/src/index.js:0-1831

    【讨论】:

      【解决方案3】:

      您只需要替换 true .from ref: required:true..... 而是使用 const 'disabled' ....in 输入名字和姓氏。

      从而实现动态变化

      【讨论】:

      • thx @nihal ,我根据您的建议修改了我的代码,但它的行为仍然不理想。另外, mode:'onblur" 是有意使用 formState.isValid ,"formState.isValid" 不适用于 mode:"onSubmit"
      【解决方案4】:

      在你的 ref 上,不要使用硬编码的 bool trueref={register({ required: true})},而是你的动态 ref={register({ required: disabled })}

      请注意,由于您的 mode: "onBlur" 配置,在 id 字段模糊之前,该按钮将无法使用

      【讨论】:

      • thx @hagai ,我根据您的建议修改了我的代码,但它的行为仍然不理想。另外, mode:'onblur" 是有意使用 formState.isValid ,"formState.isValid" 不适用于 mode:"onSubmit"
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-21
      • 2022-01-26
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      相关资源
      最近更新 更多