跳至内容

useForm

React 用于表单验证的钩子

</> useForm: UseFormProps

useForm 是一个用于轻松管理表单的自定义钩子。它接受一个对象作为**可选**参数。以下示例展示了其所有属性及其默认值。

通用属性

选项描述
mode提交之前的验证策略。
reValidateMode提交之后的验证策略。
defaultValues表单的默认值。
values用于更新表单值的响应式值。
errors用于更新表单错误的响应式错误。
resetOptions在更新新的表单值时,重置表单状态更新的选项。
criteriaMode显示所有验证错误或一次显示一个错误。
shouldFocusError启用或禁用内置焦点管理。
delayError延迟错误出现,不立即出现。
shouldUseNativeValidation使用浏览器内置的表单约束 API。
shouldUnregister在卸载后启用和禁用输入注销。
disabled禁用整个表单及其所有关联的输入。

模式验证属性

选项描述
resolver与你选择的模式验证库集成。
context用于模式验证的上下文对象。

属性


mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit' React Native: 与 Controller 兼容


此选项允许你在用户提交表单之前配置验证策略。验证在 onSubmit 事件期间发生,该事件由调用 handleSubmit 函数触发。

名称类型描述
onSubmitstringsubmit 事件上触发验证,输入附加 onChange 事件监听器以重新验证自身。
onBlurstringblur 事件上触发验证。
onChangestring在每个输入的 change 事件上触发验证,导致多次重新渲染。警告:这通常会对性能造成重大影响。
onTouchedstring在第一个 blur 事件上最初触发验证。之后,在每次 change 事件上触发验证。

注意:在与 Controller 一起使用时,确保使用 render 属性连接 onBlur
allstringblurchange 事件上都触发验证。

reValidateMode: onChange | onBlur | onSubmit = 'onChange' React Native: 自定义注册或使用 Controller


此选项允许你在输入带有错误的输入在用户提交表单后(onSubmit 事件和 handleSubmit 函数执行)重新验证时配置验证策略。默认情况下,重新验证在输入更改事件期间发生。

defaultValues: FieldValues | () => Promise<FieldValues>


defaultValues 属性使用默认值填充整个表单。它支持同步和异步分配默认值。虽然你可以使用 defaultValuedefaultChecked (如 React 官方文档中所述) 设置输入的默认值,但建议使用 defaultValues 属性填充整个表单。

useForm({
defaultValues: {
firstName: '',
lastName: ''
}
})
// set default value async
useForm({
defaultValues: async () => fetch('/api-endpoint');
})
规则
  • 应该避免提供 undefined 作为默认值,因为它与受控组件的默认状态冲突。

  • defaultValues 会被缓存。要重置它们,请使用 reset API。

  • defaultValues 默认情况下将包含在提交结果中。

  • 建议避免使用包含原型方法的自定义对象,例如 MomentLuxon,作为 defaultValues

  • 还有其他选项可以包含表单数据

    <input {...register("hidden", { value: "data" })} type="hidden" />
    // include data onSubmit
    const onSubmit = (data) => {
    const output = {
    ...data,
    others: "others",
    }
    }

values: FieldValues


values 属性会对更改做出反应并更新表单值,当你的表单需要通过外部状态或服务器数据更新时,这很有用。values 属性会覆盖 defaultValues 属性,除非 resetOptions: { keepDefaultValues: true } 也为 useForm 设置。

// set default value sync
function App({ values }) {
useForm({
values, // will get updated when values props updates
})
}
function App() {
const values = useFetch("/api")
useForm({
defaultValues: {
firstName: "",
lastName: "",
},
values, // will get updated once values returns
})
}

errors: FieldErrors


errors 属性会对更改做出反应并更新服务器错误状态,当你的表单需要通过外部服务器返回的错误更新时,这很有用。

function App() {
const { errors, data } = useFetch("/api")
useForm({
errors, // will get updated once errors returns
})
}

resetOptions: KeepStateOptions


此属性与值更新行为相关。当 valuesdefaultValues 更新时,reset API 会在内部被调用。重要的是在异步更新 valuesdefaultValues 后指定所需的行为。配置选项本身是对 reset 方法选项的引用。

// by default asynchronously value or defaultValues update will reset the form values
useForm({ values })
useForm({ defaultValues: async () => await fetch() })
// options to config the behaviour
// eg: I want to keep user interacted/dirty value and not remove any user errors
useForm({
values,
resetOptions: {
keepDirtyValues: true, // user-interacted input will be retained
keepErrors: true, // input errors will be retained with value update
},
})

context: object


此上下文 object 是可变的,并将被注入到 resolver 的第二个参数或 Yup 验证的上下文对象中。 CodeSandbox

criteriaMode: firstError | all


  • 当设置为 firstError(默认)时,只会收集每个字段的第一个错误。
  • 当设置为 all 时,会收集每个字段的所有错误。
CodeSandbox

shouldFocusError: boolean = true


当设置为 true(默认)时,如果用户提交的表单验证失败,焦点将设置在第一个带有错误的字段上。

注意
  • 只有带有 ref 的已注册字段才有效。自定义注册的输入不适用。例如:register('test') // 不起作用
  • 焦点顺序基于 register 顺序。

delayError: number


此配置将错误状态显示给最终用户的延迟时间延长指定毫秒数。如果用户纠正了错误输入,则错误会立即被删除,并且不会应用延迟。 CodeSandbox

shouldUnregister: boolean = false


默认情况下,当输入被移除时,输入值将被保留。但是,您可以将shouldUnregister设置为true,以便在卸载时unregister输入。

  • 这是一个全局配置,它会覆盖子级配置。要实现单独的行为,请在组件或钩子级别设置配置,而不是在useForm中。

  • 默认情况下,shouldUnregister: false意味着卸载的字段不会被内置验证进行验证

  • 通过在useForm级别将shouldUnregister设置为 true,defaultValues不会与提交结果合并。

  • shouldUnregister设置为 true 会使您的表单的行为更接近于原生表单。

    • 表单值存储在输入本身中。

    • 卸载输入会删除其值。

    • 隐藏输入应该使用hidden属性来存储隐藏数据。

    • 只有注册的输入才会作为提交数据包含。

    • 卸载的输入必须在useFormuseWatchuseEffect中通知,以便钩子表单验证输入是否已从 DOM 中卸载。

      const NotWork = () => {
      const [show, setShow] = React.useState(false)
      // ❌ won't get notified, need to invoke unregister
      return show && <input {...register("test")} />
      }
      const Work = ({ control }) => {
      const { show } = useWatch({ control })
      // ✅ get notified at useEffect
      return show && <input {...register("test1")} />
      }
      const App = () => {
      const [show, setShow] = React.useState(false)
      const { control } = useForm({ shouldUnregister: true })
      return (
      <div>
      // ✅ get notified at useForm's useEffect
      {show && <input {...register("test2")} />}
      <NotWork />
      <Work control={control} />
      </div>
      )
      }

shouldUseNativeValidation: boolean = false


此配置将启用浏览器原生验证。它还会启用 CSS 选择器:valid:invalid,使样式输入更容易。即使禁用客户端验证,您仍然可以使用这些选择器。

  • 仅适用于onSubmitonChange模式,因为reportValidity执行将使错误输入获得焦点。
  • 每个注册字段的验证消息需要是字符串才能以原生方式显示它们。
  • 此功能仅适用于与实际 DOM 引用连接的register API 和useController/Controller

示例


import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit } = useForm({
shouldUseNativeValidation: true,
})
const onSubmit = async (data) => {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("firstName", {
required: "Please enter your first name.",
})} // custom message
/>
<input type="submit" />
</form>
)
}

disabled: boolean = false


此配置允许您在设置为true时禁用整个表单和所有关联的输入。
这对于在异步任务或其他输入应该暂时无响应的情况下阻止用户交互非常有用。

示例


import { useForm, Controller } from "react-hook-form"
const App = () => {
const [disabled, setDisabled] = useState(false)
const { register, handleSubmit, control } = useForm({
disabled,
})
return (
<form
onSubmit={handleSubmit(async () => {
setDisabled(true)
await sleep(100)
setDisabled(false)
})}
>
<input
type={"checkbox"}
{...register("checkbox")}
data-testid={"checkbox"}
/>
<select {...register("select")} data-testid={"select"} />
<Controller
control={control}
render={({ field }) => <input disabled={field.disabled} />}
name="test"
/>
<button type="submit">Submit</button>
</form>
)
}

resolver: Resolver


此函数允许您使用任何外部验证库,例如YupZodJoiVestAjv 等等。目标是确保您可以无缝地集成您喜欢的任何验证库。如果您没有使用库,您可以始终编写自己的逻辑来验证您的表单。

npm install @hookform/resolvers
属性

名称类型描述
valuesobject此对象包含整个表单值。
contextobject这是您可以提供给useForm配置的context对象。它是一个可变的object,可以在每次重新渲染时更改。
options
{
  "criteriaMode": "string",
  "fields": "object",
  "names": "string[]"
}
这是包含有关验证字段、名称和来自useFormcriteriaMode的信息的选项对象。
规则
  • 模式验证侧重于字段级错误报告。父级错误检查仅限于直接父级级别,这适用于组复选框等组件。
  • 此函数将被缓存。
  • 输入的重新验证将在用户交互期间一次只进行一个字段。库本身将评估error对象以相应地触发重新渲染。
  • 解析器不能与内置验证器(例如:required、min 等)一起使用。
  • 在构建自定义解析器时
    • 确保您返回一个包含valueserrors属性的对象。它们的默认值应为空对象。例如:{}
    • error对象的键应与字段的name值匹配。

示例


import React from "react"
import { useForm } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"
type Inputs = {
name: string
age: string
}
const schema = yup
.object()
.shape({
name: yup.string().required(),
age: yup.number().required(),
})
.required()
const App = () => {
const { register, handleSubmit } = useForm<Inputs>({
resolver: yupResolver(schema), // yup, joi and even your own.
})
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register("name")} />
<input type="number" {...register("age")} />
<input type="submit" />
</form>
)
}
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
const schema = z.object({
name: z.string(),
age: z.number(),
})
type Schema = z.infer<typeof schema>
const App = () => {
const { register, handleSubmit } = useForm<Schema>({
resolver: zodResolver(schema),
})
const onSubmit = (data: Schema) => {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} />
<input {...register("age", { valueAsNumber: true })} type="number" />
<input type="submit" />
</form>
)
}
import React from "react";
import { useForm } from "react-hook-form";
import { joiResolver } from "@hookform/resolvers/joi";
import Joi from "joi";
interface IFormInput {
name: string;
age: number;
}
const schema = Joi.object({
name: Joi.string().required(),
age: Joi.number().required()
});
const App = () => {
const { register, handleSubmit, formState: { errors } } = useForm<IFormInput>({
resolver: joiResolver(schema)
});
const onSubmit = (data: IFormInput) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name"} />
<input type="number" {...register("age"} />
<input type="submit" />
</form>
);
}
import { useForm } from "react-hook-form"
import { ajvResolver } from "@hookform/resolvers/ajv"
// must use `minLength: 1` to implement required field
const schema = {
type: "object",
properties: {
username: {
type: "string",
minLength: 1,
errorMessage: { minLength: "username field is required" },
},
password: {
type: "string",
minLength: 1,
errorMessage: { minLength: "password field is required" },
},
},
required: ["username", "password"],
additionalProperties: false,
}
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: ajvResolver(schema),
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("username")} />
{errors.username && <p>{errors.username.message}</p>}
<input {...register("password")} />
{errors.password && <p>{errors.password.message}</p>}
<button type="submit">submit</button>
</form>
)
}
import * as React from "react"
import { useForm } from "react-hook-form"
import { vestResolver } from "@hookform/resolvers/vest"
import vest, { test, enforce } from "vest"
const validationSuite = vest.create((data = {}) => {
test("username", "Username is required", () => {
enforce(data.username).isNotEmpty()
})
test("username", "Must be longer than 3 chars", () => {
enforce(data.username).longerThan(3)
})
test("password", "Password is required", () => {
enforce(data.password).isNotEmpty()
})
test("password", "Password must be at least 5 chars", () => {
enforce(data.password).longerThanOrEquals(5)
})
test("password", "Password must contain a digit", () => {
enforce(data.password).matches(/[0-9]/)
})
test("password", "Password must contain a symbol", () => {
enforce(data.password).matches(/[^A-Za-z0-9]/)
})
})
const App = () => {
const { register, handleSubmit } = useForm({
resolver: vestResolver(validationSuite),
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("username")} />
<input {...register("password")} />
<input type="submit" />
</form>
)
}
import * as React from "react"
import { useForm } from "react-hook-form"
import * as Joi from "joi"
interface IFormInputs {
username: string
}
const validationSchema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required(),
})
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<IFormInputs>({
resolver: async (data) => {
const { error, value: values } = validationSchema.validate(data, {
abortEarly: false,
})
return {
values: error ? {} : values,
errors: error
? error.details.reduce((previous, currentError) => {
return {
...previous,
[currentError.path[0]]: currentError,
}
}, {})
: {},
}
},
})
const onSubmit = (data: IFormInputs) => console.log(data)
return (
<div className="App">
<h1>resolver</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<label>Username</label>
<input {...register("username")} />
{errors.username && <p>errors.username.message</p>}
<input type="submit" />
</form>
</div>
)
}

需要更多?请参见解析器文档

提示

您可以通过以下代码片段调试您的模式

resolver: async (data, context, options) => {
// you can debug your validation schema here
console.log("formData", data)
console.log(
"validation result",
await anyResolver(schema)(data, context, options)
)
return anyResolver(schema)(data, context, options)
}

返回


以下列表包含对useForm返回的属性的引用。

感谢您的支持

如果您发现 React Hook Form 对您的项目有用,请考虑给它加星并支持它。