Skip to content

常见问题

经常遇到的问题

React Hook Form的性能

性能是创建这个库的主要目标之一。 React Hook Form依赖于非受控组件,这就是为什么register函数作用在ref上。 这样将减少由于用户在输入框输入或表单其他值改变而引起的重渲染次数。 因为开销更小,组件会比受控组件更快速地挂载到页面上。 作为参考,我已经完成了一个快速比较测试


如何创建一个输入组件的辅助错误和消息?

React Hook Form基于非受控组件,它使您能够轻松的构建高可访问性的自定义表单。

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label htmlFor="firstName">First name</label>
      <input
        id="firstName"
        aria-invalid={errors.firstName ? "true" : "false"}
        {...register('firstName', { required: true })}
      />
      {errors.firstName && (
        <span role="alert">
          This field is required
        </span>
      )}

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

它是否可以与Class类组件一起使用?

不, 不可以直接使用。但是你可以构建一个包裹组件然后在你的类组件中使用。


如何重置表单?

有两种方法清空表单。

  • HTMLFormElement.reset()

    此方法与单击表单的重置按钮相同,并且只清除input/select/checkbox的值。

  • React Hook Form API: reset()

    React Hook Form的重置方法将重置所有表单项值,并清空表单内的所有错误。


如何初始化表单值?

由于React Hook Form依赖于非受控组件, 所以可以为单独的表单项指定defaultValuedefaultChecked。 但是,更常见的方法是在useForm传入defaultValue来初始化表单。

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm({
    defaultValues: {
      firstName: "bill",
      lastName: "luo",
      email: "bluebill1049@hotmail.com"
    }
  });
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName")} />
      <input {...register("lastName")} />
      <input {...register("email")} />

      <button type="submit">Submit</button>
    </form>
  );
}

如何共用ref?

React Hook Form需要ref来收集输入值,但是,您可能需要将ref用于其他用途(例如,如果您想要使用它滚动到视图中)。

import React, { useRef } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();
  const firstNameRef = useRef(null);
  const onSubmit = data => console.log(data);
  const { ref, ...rest } = register('firstName');

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...rest} name="firstName" ref={(e) => {
        ref(e)
        firstNameRef.current = e // you can still assign to ref
      }} />

      <button>Submit</button>
    </form>
  );
}import React, { useRef } from "react";
import { useForm } from "react-hook-form";

type Inputs = {
  firstName: string,
  lastName: string,
};

export default function App() {
  const { register, handleSubmit } = useForm<Inputs>();
  const firstNameRef = useRef<HTMLInputElement | null>(null);
  const onSubmit = data => console.log(data);
  const { ref, ...rest } = register('firstName');

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...rest} name="firstName" ref={(e) => {
        ref(e)
        firstNameRef.current = e // you can still assign to ref
      }} />

      <button>Submit</button>
    </form>
  );
}

如果无法访问ref怎么办?

您实际上可以在没有ref的情况下register输入组件。 事实上,您可以手动调用setValuesetErrortrigger

注意: 由于ref尚未注册,因此React Hook Form将无法监听输入组件的事件。 这意味着您需要更新值和错误。

import React, { useEffect } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, setValue, setError } = useForm();
  const onSubmit = data => console.log(data);

  useEffect(() => {
    register("firstName", { required: true });
    register("lastName");
  }, []);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        name="firstName"
        onChange={e => setValue("firstName", e.target.value)}
      />
      <input
        name="lastName"
        onChange={e => {
          const value = e.target.value;
          if (value === "test") {
            setError("lastName", "notMatch")
          } else {
            setValue("lastName", e.target.value)
          }
        }}
      />
      <button>Submit</button>
    </form>
  );
}

浏览器支持?

React Hook Form支持所有主流浏览器。

您可以引入 react-hook-form 的 IE 11 版本以以支持 IE11 。

import { useForm } from 'react-hook-form/dist/index.ie11'; // V6
import { useForm } from 'react-hook-form/dist/react-hook-form.ie11'; // V5'
// Resolvers
import { yupResolver } from '@hookform/resolvers/dist/ie11/yup';

为什么第一次按键不起作用?

仔细检查是否使用了value而不是defaultValue

React Hook Form是基于非受控输入组件构建的,这意味着您不需要通过statueonChange更改输入值。 因此,您根本不需要value,事实上,您只需要设置defaultValue


因MutationObserver测试失败?

如果您在测试过程中遇到困难,并且问题是由MutationObserver引起的。 确保安装MutationObserver并在setup.js file中引用它。


React Hook Form, Formik 还是 Redux Form?

首先,这几个库都在尝试解决同样的问题,尽可能使表单开发变的简单。 然而,三者之间还是有一些根本性区别,react-hook-form是 建立在非受控的输入组件上,并尝试提供给表单最佳的性能和最少重渲染次数。除此之外,react-hook-form是由React Hook构建并作为hook调用, 这意味无须导入组件。 这里有一些的细节差异:

React Hook Form

Formik

Redux Form

组件非受控受控受控受控
渲染最少的重渲染在输入组件中输入时,每次本地状态变化都会导致重渲染。在输入组件中输入时,每次状态管理工具(Redux)变化都会导致重渲染。
APIHooksComponent (RenderProps, Form, Field) + HooksComponent (RenderProps, Form, Field)
包体积
react-hook-form@3.26.2
5.3KB

formik@2.0.1
14.4KB

redux-form@8.2.6
27KB
校验自带 Yup, Joi, Superstruct 校验以及自定义构建。使用Yup自定义构建自定义构建或使用插件
学习曲线
状态成长中的中型社区大社区:社区中非常稳定的表单库大社区:社区中非常稳定的表单库

可以用于受控组件吗?

简短的回答:可以

React-hook-form不建议您构建受控表单,但是您仍然可以轻松实现。

可以使用watch API监听每个输入组件的变化并传递给value属性。

或者,您可以使用我们的包装器组件Controller,它会为您处理那些自定义注册。

import React from "react";
import { useForm, Controller } from "react-hook-form";

function App() {
  const { control } = useForm();
  
  return (
    <Controller
      render={({ field }) => <input {...field} />}
      name="firstName"
      control={control}
      defaultValue=""
    />
  );
}
import React, { useEffect } from "react";
import { useForm } from "react-hook-form";

function App() {
  const { register, watch, setValue, handleSubmit } = useForm({
    defaultValues: {
      firstName: "",
      lastName: ""
    }
  });
  const { firstName, lastName } = watch();

  useEffect(() => {
    register("firstName");
    register("lastName");
  }, [register]);

  const handleChange = (e, name) => {
    setValue(name, e.target.value);
  };

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        onChange={(e) => handleChange(e, "firstName")}
        value={firstName}
      />

      <input onChange={(e) => handleChange(e, "lastName")} value={lastName} />
      <input type="submit" />
    </form>
  );
}

测试 React Hook Form

  • 为什么无法在React Native (react-native-testing-library)测试?

    React Hook Form 并不会在服务端渲染时注册输入组件,这意味着在react native中测试会导致window对象变为undefined。一个快速的解决方案是将window对象存储起来以使注册过程可以完成。

  • 为什么我会收到act警告?

    React Hook表单中的所有验证方法将被视为异步函数, 因此使用async包装act很重要。

  • 为什么输入组件更改没有触发事件?

    React Hook Form 使用input事件处理输入组件变化。如果使用了 react-testing-library 您可以轻松切换到fireEvent.input

    如果你使用了enzyme,就需要手动地设置输入组件对应的 DOM 节点的值,然后触发input事件。

我们需要您的支持

如果您发现React Hook Form在您的研究项目中有用,请支持我们和贡献者❤

Edit