“isValid”始终为假。

25

我正在使用 react-hook-form 中的自定义 register,但是当我在输入框中输入文本(并满足 required 条件)时,无法获取 formState.isValidtrue

这里是一个示例代码:

interface FormValues {
  readonly value: string;
}

export default function App() {
  console.log("rendering");

  const form: UseFormMethods<FormValues> = useForm<FormValues>({
    mode: "onChange",
    reValidateMode: "onChange",
    defaultValues: { value: "" }
  });

  useEffect(() => {
    form.register({ name: "value" }, { required: true });
  }, [form, form.register]);

  const { isValid } = form.formState;
  const value = form.watch("value");

  return (
    <div>
      <input
        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
          form.setValue("value", e.target.value);
        }}
      />
      <div>IsValid: {JSON.stringify(isValid)}</div>
      <div>Errors: {JSON.stringify(form.errors)}</div>
      <div>Value: {JSON.stringify(value)}</div>
    </div>
  );
}

这个问题特别针对于这种register的使用方式,而不是其他类型(refController)。

这里有一个完整的例子。

有人知道为什么会这样吗?我错过了什么吗?

此外,但这不太相关 - 有人知道为什么每次输入更改都会触发两次渲染吗?

编辑

在与Dennis Vash讨论后,这个问题有了一些进展,但仍未解决。

https://react-hook-form.com/api/#setValue上的文档实际上指定了一个触发验证的选项:

(name: string, value: any, shouldValidate?: boolean) => void


You can also set the shouldValidate parameter to true in order to trigger a field validation. eg: setValue('name', 'value', true)

在我撰写此文时,文档引用react-form-hook的版本为5,而我目前使用的是6.0.0-rc.5,因此签名发生了一些变化,类似于以下内容:

(name: string, value: any, { shouldValidate: boolean; shouldDirty: boolean; }) => void

然而,在我的一个例子中,当使用 shouldValidate: true 时,我遇到了无限循环的问题:

Translated text: However, in one of my examples, I encountered an infinite loop issue when using shouldValidate: true.
interface FormValues {
  readonly value: string;
}

export default function App() {
  console.log("rendering");

  const form: UseFormMethods<FormValues> = useForm<FormValues>({
    mode: "onChange",
    reValidateMode: "onChange",
    defaultValues: { value: "" }
  });

  useEffect(() => {
    form.register({ name: "value" }, { required: true, minLength: 1 });
  }, [form, form.register]);

  const { isValid } = form.formState;
  const value = form.getValues("value");

  return (
    <div>
      <input
        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
          form.setValue("value", e.target.value, {
            shouldValidate: true
          });
        }}
      />
      <div>IsValid: {JSON.stringify(isValid)}</div>
      <div>Errors: {JSON.stringify(form.errors)}</div>
      <div>Value: {JSON.stringify(value)}</div>
    </div>
  );
}

isValidtrue 时循环进行,当其为 false 时停止。

您可以在此处试用。输入一个键将开始连续重新渲染,清除输入将停止循环...

enter image description here

2个回答

22

一个老问题,所以我现在脑子里没有上下文了。然而,正如你在我的问题中看到的,似乎我已经在使用onChange,但它并没有起作用。也许我当时还是做错了什么,或者可能是react-hook-form中的一个错误,后来被修复了。完整的示例链接也不再有效,所以我不能确定。 - mrzli

5

由于 React.StrictMode 的影响,该组件被渲染了两次。

StrictMode 无法自动检测到副作用,但它可以通过使其更加确定性来帮助您发现它们。这是通过有意呈现以下函数两次来实现的:...

此外,为了进行验证,您需要提交表单(尝试按下 enter 键),如果您使用 onChange 模式而没有使用引用,则应改用 triggerValidation

export default function App() {
  const {
    register,
    formState,
    watch,
    errors,
    setValue,
    handleSubmit
  }: UseFormMethods<FormValues> = useForm<FormValues>();

  useEffect(() => {
    register(
      { name: "firstName", type: "custom" },
      { required: true, min: 1, minLength: 1 }
    );
    console.log("called");
  }, [register]);

  const { isValid } = formState;
  const values = watch("firstName");

  const onSubmit = (data, e) => {
    console.log("Submit event", e);
    console.log(JSON.stringify(data));
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
          setValue("firstName", e.target.value);
        }}
      />
      {/*<button>Click</button>*/}
      <div>IsValid: {JSON.stringify(isValid)}</div>
      <div>Errors: {JSON.stringify(errors)}</div>
      <div>Form value: {JSON.stringify(values)}</div>
    </form>
  );
}

Edit old-brook-ho66h


对于 React.StrictMode,我给它加了个 +1。我试着把它移除,确实可以减少额外的渲染。但是关于我的主要问题,我试着在 input 中添加 name,但并没有起作用。如果它真的有用的话,我会觉得很奇怪。当我调用 form.setValue() 时,我已经使用了名称 'value',为什么在这种情况下还需要设置输入的 name 呢?我可以理解在使用 ref 的表单中需要设置它。 - mrzli
请查看 https://react-hook-form.com/api/#useForm 中的文档,并注意我正在使用 mode: "onChange"。文档中说明:验证将在每次输入更改事件触发时触发,并导致多次重新呈现。警告:这通常会对性能产生重大影响。 我不想只在提交时进行验证,而且我已经明确使用了配置,或者至少我是这样理解配置的。所以我的问题仍然存在:为什么这不起作用?我错过了其他什么吗? - mrzli
是的,你漏掉了一些东西,“在每个输入的更改事件上”,但你没有使用引用,所以为了让它工作,你需要自己调用验证。 - Dennis Vash
我正在使用版本6,所以那里有一个trigger方法而不是triggerValidation。它似乎可以工作,但会引起其他问题。如果我使用watch(),它会挂起应用程序,可能存在一些无限循环。使用const value = form.getValues("value");获取值似乎暂时提供了值,然后又恢复为空字符串。 - mrzli
1
是的,不太清楚- 对我来说,标准行为应该是:我正在使用一个触发任何更改时验证的验证模式。我做了一些更改,然后触发验证 :) - mrzli
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接