Skip to content

常见问题

常见问题

React Hook 表单的性能

性能是创建该库的主要原因之一。React Hook Form 依赖于不受控制的表单,这就是 register 函数捕获 ref 且受控组件的重新渲染范围为 ControlleruseController 的原因。此方法减少了由于用户键入输入或在表单或应用的根部更改其他表单值而发生的重新渲染量。组件安装到页面的速度比受控组件更快,因为它们的开销更少。作为参考,有一个快速对比测试,你可以参考 这个仓库链接

¥Performance is one of the primary reasons why this library was created. React Hook Form relies on an uncontrolled form, which is the reason why the register function captures ref and the controlled component has its re-rendering scope with Controller or useController. This approach reduces the amount of re-rendering that occurs due to a user typing in an input or other form values changing at the root of your form or applications. Components mount to the page faster than controlled components because they have less overhead. As a reference, there is a quick comparison test that you can refer to at this repo link.


如何创建可访问的输入错误和消息?

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

¥React Hook Form is based on Uncontrolled Components, which gives you the ability to easily build an accessible custom 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>
)
}

它可以与类组件一起使用吗?

不,不是开箱即用的。如果你想这样做,你可以围绕它构建一个封装器并在你的类组件中使用它。

¥No, not out of the box. If you want to do this, you can build a wrapper around it and use it in your Class Component.

你不能在类组件内部使用 Hooks,但你绝对可以在单个树中将类和函数组件与 Hooks 混合使用。组件是使用 Hooks 的类还是函数只是该组件的实现细节。从长远来看,我们期望 Hooks 成为人们编写 React 组件的主要方式。

¥You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is simply an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.


如何重置表单?

清除表单有两种方法:

¥There are two methods to clear the form:

  • HTMLFormElement.reset()

    此方法与单击表单的重置按钮执行相同的操作。它仅清除 input/select/checkbox 值。

    ¥This method does the same thing as clicking a form's reset button. It only clears input/select/checkbox values.

  • React Hook 表单 API:reset()

    ¥React Hook Form API: reset()

    React Hook Form 的 reset 方法将重置所有字段值,并且还将清除表单内的所有 errors

    ¥React Hook Form's reset method will reset all field values, and will also clear all errors within the form.


如何初始化表单值?

由于 React Hook Form 依赖于不受控制的表单,因此你可以为单个字段指定 defaultValuedefaultChecked。但是,更常见并建议通过将 defaultValues 传递到 useForm 来初始化表单。

¥Being that React Hook Form relies on an uncontrolled form, you can specify a defaultValue or defaultChecked to an individual field. However, it is more common and recommended to initialize a form by passing defaultValues to useForm.

function App() {
const { register, handleSubmit } = useForm({
defaultValues: {
firstName: "bill",
lastName: "luo",
},
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<button type="submit">Submit</button>
</form>
)
}

对于异步默认值,你可以使用以下方法:

¥For async default values, you can use the following methods:

  • 异步 defaultValues

    ¥Async defaultValues

    function App() {
    const { register, handleSubmit } = useForm({
    defaultValues: async () => {
    const response = await fetch("/api")
    return await response.json() // return { firstName: '', lastName: '' }
    },
    })
    }
  • 反应性 values

    ¥Reactive values

    function App() {
    const { data } = useQuery() // data returns { firstName: '', lastName: '' }
    const { register, handleSubmit } = useForm({
    values: data,
    resetOptions: {
    keepDirtyValues: true, // keep dirty fields unchanged, but update defaultValues
    },
    })
    }

如何分享参考使用情况?

React Hook Form 需要一个 ref 来收集输入值。但是,你可能希望将 ref 用于其他目的(例如滚动到视图中或获得焦点)。

¥React Hook Form needs a ref to collect the input value. However, you may want to use ref for other purposes (e.g. scroll into the view, or focus).

import { useRef, useImperativeHandle } 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)
const onSubmit = (data: Inputs) => console.log(data)
const { ref, ...rest } = register("firstName")
const onClick = () => {
firstNameRef.current!.value = ""
}
useImperativeHandle(ref, () => firstNameRef.current)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...rest} ref={firstNameRef} />
<button type="button" onClick={onClick}>
clear
</button>
<button>Submit</button>
</form>
)
}
import { useRef, useImperativeHandle } 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")
const onClick = () => {
firstNameRef.current!.value = ""
}
useImperativeHandle(ref, () => firstNameRef.current)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...rest} ref={firstNameRef} />
<button type="button" onClick={onClick}>
clear
</button>
<button>Submit</button>
</form>
)
}

如果你无权访问参考怎么办?

实际上,你可以在没有 ref 的情况下对输入进行 register。事实上,你可以手动设置 setValuesetErrortrigger

¥You can actually register an input without a ref. In fact, you can manually setValue, setError and trigger.

注意:由于 ref 尚未注册,React Hook Form 将无法向输入注册事件监听器。这意味着你必须手动更新值和错误。

¥Note: Because ref has not been registered, React Hook Form won't be able to register event listeners to the inputs. This means you will have to manually update value and error.

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

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

确保你没有使用 value。正确的属性是 defaultValue

¥Make sure you are not using value. The correct property is defaultValue.

React Hook Form 专注于不受控制的输入,这意味着你不需要更改输入 value 通过 state 通过 onChange。事实上,你根本不需要 value。你只需将 defaultValue 设置为初始输入值即可。

¥React Hook Form is focusing on uncontrolled inputs, which means you don't need to change the input value via state via onChange. In fact, you don't need value at all. You only need to set defaultValue for the initial input value.

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"

React Hook Form、Formik 还是 Redux Form?

首先,所有库都试图解决同样的问题:让表单构建体验尽可能简单。然而,这三者之间存在一些根本区别。react-hook-form 在构建时考虑了不受控制的输入,并尝试为你的表单提供最佳性能和最少的重新渲染次数。另外,react-hook-form 是用 React Hooks 构建的,并用作钩子,这意味着没有任何组件可供你导入。以下是一些详细的差异:

¥First of all, all libs try to solve the same problem: make the form building experience as easy as possible. However, there are some fundamental differences between these three. react-hook-form is built with uncontrolled inputs in mind and tries to provide your form with the best performance and least amount of re-renders possible. Additionallly, react-hook-form is built with React Hooks and used as a hook, which means there is no Component for you to import. Here are some of the detailed differences:

React Hook FormFormikRedux 表单
组件uncontrolledcontrolledcontrolledcontrolled
渲染最小化重新渲染和优化计算根据本地状态更改重新渲染(当你输入输入时。)根据状态管理库 (Redux) 更改重新渲染(当你输入输入时。)
API钩子组件(RenderProps、Form、Field)+ Hooks组件(RenderProps、表单、字段)
封装尺寸
react-hook-form@7.27.0
8.5KB
中型
formik@2.1.4 KB

redux-form@8.3.6 .4KB
验证内置、YupZodJoiSuperstruct 和构建你自己的。打造自己或 Yup自己构建或插件
学习曲线低到中中等的中等的

watch 与 getValues 与状态

  • 监视:通过事件监听器订阅所有输入或指定输入的更改,并根据订阅的字段重新渲染。查看 这个代码沙盒 的实际行为。

    ¥watch: subscribe to either all inputs or a specified input's changes via an event listener and re-render based on which fields are subscribed to. Check out this codesandbox for actual behaviour.

  • 获取值:获取存储在自定义钩子内的值作为参考,快速且便宜。此方法不会触发重新渲染。

    ¥getValues: get values that are stored inside the custom hook as reference, fast and cheap. This method doesn’t trigger a re-render.

  • 局部状态:React 本地状态不仅仅代表输入的状态,还决定渲染什么。这将在每个输入的更改时触发。

    ¥local state: React local state represents more than just an input’s state and also decides what to render. This will trigger on each input’s change.


为什么三元运算符的默认值没有正确更改?

React Hook Form 不能控制整个表单和输入,这就是为什么 React 无法识别实际输入已被交换或交换的原因。作为解决方案,你可以通过为输入提供唯一的 key 属性来解决此问题。你还可以阅读 这篇文章由 Kent C.多兹 中有关关键属性的更多信息。

¥React Hook Form doesn't control your entire form and inputs, which is why React wouldn't recognize that the actual input has been exchanged or swapped. As a solution, you can resolve this problem by giving a unique key prop to your input. You can also read more about the key props from this article written by Kent C. Dodds.

import React from "react"
import { useForm } from "react-hook-form"
export default function App() {
const { register } = useForm()
return (
<div>
{watchChecked ? (
<input {...register("input3")} key="key1" defaultValue="1" />
) : (
<input {...register("input4")} key="key2" defaultValue="2" />
)}
</div>
)
}

如何使用模式或选项卡表单?

重要的是要理解,React Hook Form 通过将输入状态存储在每个输入中(除了 useEffect 处的自定义 register)来拥抱原生表单行为。一个常见的误解是输入状态保留在已安装或未安装的输入中。例如使用模式或选项卡表单时。相反,正确的解决方案是在每个模式或选项卡中为你的表单构建一个新表单,并以本地或全局状态捕获你的提交数据,然后对合并的数据执行某些操作。

¥It's important to understand that React Hook Form embraces native form behavior by storing input state inside each input (except custom register at useEffect). A common misconception is that input state remains with mounted or unmounted inputs. Such as when working with a modal or tab forms. Instead, the correct solution is to build a new form for your form inside each modal or tab and capture your submission data in local or global state and then do something with the combined data.

或者,你可以在调用“useForm”时使用已弃用的选项 shouldUnregister: false

¥Alternatively you can use the deprecated option shouldUnregister: false when calling useForm.

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 中文网 - 粤ICP备13048890号