React 表单工程化:用 react-hook-form 把受控表单的性能陷阱填平

test12026-09-222 次阅读

受控表单为什么越写越卡

React 里最常见的一种表单写法是把每个字段都塞进 useState,再在 onChange 里 setState。单个输入框没问题,但当表单字段变多、或在长列表里嵌表单时,每次按键都会触发整棵组件树重渲染。受控意味着输入值来自 state、再回写 state,输入法组合、自动补全都会加剧渲染次数。

把表单交给 react-hook-form

react-hook-form 的核心思路是非受控优先:它用 ref 直接读写 DOM 节点,只在提交或校验时读取字段值,因此输入过程几乎不触发 React 渲染。下面是一段可直接运行的登录表单。

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

type LoginForm = {
  email: string;
  password: string;
};

export function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm<LoginForm>({ defaultValues: { email: "", password: "" } });

  const onSubmit = handleSubmit(async (values) => {
    await fetch("/api/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(values),
    });
  });

  return (
    <form onSubmit={onSubmit}>
      <input
        {...register("email", {
          required: "邮箱必填",
          pattern: { value: /^\S+@\S+$/, message: "邮箱格式不正确" },
        })}
      />
      {errors.email && <span>{errors.email.message}</span>}
      <input type="password" {...register("password", { required: "密码必填" })} />
      <button disabled={isSubmitting}>登录</button>
    </form>
  );
}

register 把 onChange、onBlur、ref、name 一起挂到 input 上,校验规则写在第二个参数里,错误信息从 formState.errors 读取,提交状态用 isSubmitting 即可禁用按钮。

自定义组件怎么接

第三方组件(日期选择器、级联选择)拿不到 ref,用 Controller 包一层,把 field.value 和 field.onChange 透传给组件即可。

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

function RoleSelect({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  return <select value={value} onChange={(e) => onChange(e.target.value)} />;
}

export function ProfileForm() {
  const { control } = useForm({ defaultValues: { role: "user" } });
  return (
    <Controller
      name="role"
      control={control}
      render={({ field }) => (
        <RoleSelect value={field.value} onChange={field.onChange} />
      )}
    />
  );
}

什么时候该用

  • 字段多、嵌套深、或在列表里批量渲染表单时,react-hook-form 的非受控模型能显著减少渲染。
  • 简单单行搜索框、单一开关这类轻量场景,受控写法更直观,没必要引入依赖。
  • 需要跨字段联动校验、动态字段数组时,配合 useFieldArray 比手写 state 省心得多。
T

test1

文章作者

受控表单为什么越写越卡 React 里最常见的一种表单写法是把每个字段都塞进 useState,再在 onChange...

分类
技术
发布时间
2026-09-22
字数
约 2156 字
阅读
2 次