@beignet/react-hook-form

中文文档
0.0.65发布于 2026/11/08MITTypeScriptES Module零依赖近 30 天下载 1927

使用标准Schema支持的 Beignet 重现 Hook Form 集成

中文使用文档
文档目录22 节
  1. 安装
  2. 类型脚本要求
  3. 代理技能
  4. 使用量
  5. 基本形式
  6. 使用反应查询突变
  7. 无效验证
  8. 直接使用合同配置
  9. API 参考
  10. createReactHookForm()
  11. rhf(contract, options?)
  12. adapter.useForm(props?)
  13. rootFormError(error, fallback, overrides?)
  14. 类型推论
  15. 重新使用合同计划
  16. 绑定单独的表单方案
  17. React Hook 窗体包装的选项
  18. 标准Schema 支持
  19. 验证行为
  20. 完整实例
  21. 相关软件包
  22. 许可证

@beignet/ react-hook-form (英语)

运行时间 : Beignet需要Node.js 22.12或更新. Bun是可选的.

Beignet 的后置钩形式集成

[叹息] Beignet是实验性的α软件. 这个 0.0.x 包行为早期 评估,且在框架结算时,API可能在发布之间发生变化.

这个软件包提供自动形式验证,并使用一个 合同体计划,或产生合同投入的单独形式计划. 所选择的窗体图案必须有对象形状的输入. 它与任何 标准Schema 图书馆 (佐德,瓦利博特,ArkType等.

安装

npm install @beignet/react-hook-form @beignet/core react-hook-form@^7.55.0 @hookform/resolvers@^7.0.1 react

支助 @hookform/resolvers v5, v6, 和 v7 带有反应钩形式 7.55.0 或更新 v7. 现有 v5 和 v6 安装仍然支持; 新启动器使用 v7. Beignet的标准Schema集成对这些升级不需要修改. 解析提交、原始模式、计划默认和变换以及可选 解析器设置保留其行为和推论. 自定义解析器跟随 移民: v6 需要效应 v4 页:1 effectTsResolver,以及 v7 移动类型框到 typebox 1.x 运算 改为 @sinclair/typebox,带有新的错误类型和消息.

类型脚本要求

此包需要 TypeScript 5.0 或更高才能进行适当的类型推断.

代理技能

这个包装了一种用于编码的 TanStack Intental 技能: @beignet/react-hook-form#forms加入合同支持表时装入, 反应 Hook Form 设置,标准Schema解析器行为, rootFormError, (中文(简体) ), 反应查询突变, 改变身体计划, 特性组件 边框,或 Beignet app 中的字段/服务器错误映射.

使用量

基本形式

这些例子使用从Beignet起步的Todos合同. 创建接受 title; 完成属于更新合同。 工作形式: 核查步骤 窗体指南。 。 。 .

"use client";

import { createReactHookForm } from "@beignet/react-hook-form";
import { createTodo } from "@/features/todos/contracts";

const rhf = createReactHookForm();

function CreateTodoForm() {
  const { useForm } = rhf(createTodo);
  const form = useForm({
    defaultValues: {
      title: "",
    },
  });

  const onSubmit = form.handleSubmit((values) => {
    // values is parsed schema output: { title: string }
    console.log("Creating todo:", values);
  });

  return (
    <form onSubmit={onSubmit}>
      <input
        {...form.register("title")}
        placeholder="What needs to be done?"
      />
      {form.formState.errors.title && (
        <p className="error">{form.formState.errors.title.message}</p>
      )}

      <button type="submit" disabled={form.formState.isSubmitting}>
        Create Todo
      </button>
    </form>
  );
}

使用反应查询突变

"use client";

import { createReactHookForm, rootFormError } from "@beignet/react-hook-form";
import { useMutation } from "@tanstack/react-query";
import { rq } from "@/client";
import { createTodo, listTodos } from "@/features/todos/contracts";

const rhf = createReactHookForm();

function CreateTodoForm() {
  const { useForm } = rhf(createTodo);
  const form = useForm({
    defaultValues: { title: "" },
  });

  const mutation = useMutation(
    rq(createTodo).mutationOptions({
      invalidates: () => [rq(listTodos).contractFilter()],
      onSuccess: () => form.reset(),
      onError: (error) => {
        form.setError("root", rootFormError(error, "Could not create the todo."));
      },
    }),
  );

  const onSubmit = form.handleSubmit((values) => {
    form.clearErrors("root");
    mutation.mutate({ body: values });
  });

  return (
    <form onSubmit={onSubmit}>
      <input {...form.register("title")} placeholder="Title" readOnly={mutation.isPending} />
      {form.formState.errors.title && (
        <p>{form.formState.errors.title.message}</p>
      )}
      {form.formState.errors.root && (
        <p>{form.formState.errors.root.message}</p>
      )}

      <button type="submit" disabled={mutation.isPending}>
        {mutation.isPending ? "Creating..." : "Create"}
      </button>
    </form>
  );
}

React Hook Form只拥有请求体域. 通过路径参数,查询参数, 头,以及端点调用或突变变量的认证衍生值. 提交失败作为 Beignet 客户端错误返回, 所以地图路由自有目录 错误、框架验证错误、网络故障和合同漂移 结束 rootFormError(...)设置 form.setError("root", ...) 或一个 当您的服务器响应确定一个时, 指定字段 .

无效验证

如果您需要禁用 schema 解析器( 例如, 用于部分形式处理 ) :

const { useForm } = rhf(createTodo);
const form = useForm({
  resolverEnabled: false, // Disable schema validation
  defaultValues: { title: "" },
});

直接使用合同配置

您可以通过合同构建者或其配置:

import { createReactHookForm } from "@beignet/react-hook-form";
import { createTodo } from "@/features/todos/contracts";

const rhf = createReactHookForm();

// Using ContractBuilder directly
const { useForm } = rhf(createTodo);

// Or using the contract config
const { useForm } = rhf(createTodo.config);

API 参考

createReactHookForm()

创建反应钩式适配器厂.

const rhf = createReactHookForm();

rhf(contract, options?)

默认使用合同正文计划创建适配器。 过 { schema } 绑定一个单独的表单计划,其产出可转让给合同机构 输入。 选定的计划输入必须是带有命名字段的对象。 斯卡尔 和阵列机构需要一种明确的对象输入形式,生成 请求形状。 没有机构的合同被拒绝.

const adapter = rhf(createTodo);

adapter.useForm(props?)

返回反应钩表 useForm 以选定的方案作为解析器.

const form = adapter.useForm({
  defaultValues: { title: "" },
  resolverEnabled: true, // default
  submitValues: "parsed", // default; use "raw" for original input
  mode: "onBlur",
});

rootFormError(error, fallback, overrides?)

将一个失败的端点调用或突变错误映射到 form.setError("root", ...) 形状。 环绕 contractErrorMessage 从 @beignet/core/client:非合同错误返回倒置副本, 客户端输入验证失败返回一个通用“ 检查突出显示 字段“消息”和目录代码可以覆盖每个表格的复制.

form.setError(
  "root",
  rootFormError(error, "Could not update profile.", {
    HANDLE_UNAVAILABLE: "That handle is already taken.",
  }),
);

类型推论

  • 现场(register, (中文(简体) ), watch, (中文(简体) ), setValue, (中文(简体) ), getValues, (中文(简体) ), defaultValues(中文(简体) ) 使用选定的方案 投入。 。 。 .
  • handleSubmit 收到解析图 产出 默认,包括 变换、默认和去除未知密钥。 活地状态不变.
  • submitValues: "raw" 验证但返回所提交的原始快照.
  • resolverEnabled: false 返回未解析的输入。 需要明确解析模式 生成的解析器。 动态或可选启用的旗帜返回输入/输出联盟 .
  • 习惯 resolver 拥有其输出类型,即使生成被禁用. 它不能与 submitValues。 。 。 .
  • 两种适配器方法都接受转发 UseFormProps 和可选的解决者. 缺失的覆盖返回到生成的解析器或未分解的输入 当世代被禁用时。 提交类型包括每个可能的输出 . 一个 undefined 选项对象用途生成验证和解析输出.
  • 有条件的配置可选择自定义解析器或生成模式; 提交类型包括每个分支的输出。 无法设置单一配置 两者 resolver 财务报告和审定财务报表 submitValues如果整个选项可能缺席, 返回属性,例如 defaultValues 财务报告和审定财务报表 mode 也可以选择.

重新使用合同计划

对于一个数字值的 API, 使用 z.number() 在合同中配置 数字字段 register("amount", { valueAsNumber: true })。提交已解析 给输入的客户端回调值; 客户端发送未修改的输入 而服务器会独立验证它.

使用 z.coerce.number() 在共同合同中,如果API有意接受 数弦也. 只有在 解析值仍为有效的请求输入,再次解析保存其 意为. z.string().transform(Number) 无法解析其数值输出; 偶数 同类型变换可以再次改变一个值. 使用单独的表单方案 此类UI转换,或原始模式来提交原始合同输入.

绑定单独的表单方案

import { defineContract } from "@beignet/core/contracts";
import { createReactHookForm } from "@beignet/react-hook-form";
import { z } from "zod";

const paymentBody = z.object({
  amount: z.number().int().positive(),
  currency: z.string().default("USD"),
});
const createPayment = defineContract({ method: "POST", path: "/api/payments" })
  .body(paymentBody)
  .responses({ 201: z.object({ id: z.string() }) });
const paymentFormSchema = paymentBody.extend({
  amount: z.string().trim().regex(/^\d+$/)
    .transform(Number)
    .pipe(paymentBody.shape.amount),
});

const rhf = createReactHookForm();
const paymentForm = rhf(createPayment, { schema: paymentFormSchema });
const form = paymentForm.useForm({ defaultValues: { amount: "" } });

form.watch("amount"); // string
form.handleSubmit((body) => {
  body.amount; // number, matching the request body input
  body.currency; // string, including the schema default
});

窗体 schema 拥有窗体验证;适配器不额外运行 合同计划。 从共享验证器中获取,以保持运行时间限制 对齐。 TypeScript 拒绝不兼容的输出形状, 但无法检查每个形状 运行时间规则。 原始或已禁用的文件使用表单的输入并可能 需要绘制地图才能公布合同.

使用 defaultValues 对于默认的 UI 显示。 生成解析器 复制纯对象、阵列和同步验证前的日期,抓取 拥有过一次 类例、文件、函数和其他不透明值 保留其身份;在审定和提交期间保持其永久不变. 自定义解析器拥有其验证和快照行为.

React Hook 窗体包装的选项

formOptions(...) 返回与本地兼容的选项 UseFormProps, (中文(简体) ), useForm,以及 createFormControl,包括 exactOptionalPropertyTypes 启用 。 输入/输出类型匹配适配器 useForm部分 defaultValues 能够缩小反钩形式本身的推论, 所以供应所有三个 通用术语:

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

const form = useForm<
  z.input<typeof paymentFormSchema>,
  unknown,
  z.output<typeof paymentFormSchema>
>(paymentForm.formOptions({ defaultValues: { amount: "" } }));

那个适配器 useForm 自动推断这些。 提交调用值 而不是通过重读可变字段状态 getValues()。 。 。 .

标准Schema 支持

此软件包使用 @hookform/resolvers/standard-schema 解析器, 它与任何标准 Schema 兼容库合作 :

  • 佐德语Name - 说吧 z.object({ ... })
  • 维利博特 - 说吧 v.object({ ... })
  • ArkType 密码 - 说吧 type({ ... })

验证行为

当生成的解析器运行时反应Hook Form控制. 默认 反应 Hook Form 设置, 解析器在提交前验证, 然后 在提交失败后重新验证已更改的字段 。 通过正常的反作用钩表单 选项,例如 mode: "onBlur" 或者说 reValidateMode: "onChange" 当一个表单 需要不同的时间.

验证错误可通过 form.formState.errors数字 :

{form.formState.errors.title && (
  <span className="error">
    {form.formState.errors.title.message}
  </span>
)}

完整实例

import { createReactHookForm } from "@beignet/react-hook-form";
import { useMutation } from "@tanstack/react-query";
import { rq } from "@/client";
import { rootFormError } from "@/client/errors";
import { updateProfile } from "@/features/profile/contracts";

const rhf = createReactHookForm();

function ProfileForm({ profile }) {
  const { useForm } = rhf(updateProfile);
  const form = useForm({
    defaultValues: {
      name: profile.name,
      email: profile.email,
      bio: profile.bio ?? "",
    },
  });

  const mutation = useMutation(
    rq(updateProfile).mutationOptions({
      onSuccess: () => {
        toast.success("Profile updated!");
      },
      onError: (error) => {
        form.setError("root", rootFormError(error, "Could not update the profile."));
      },
    })
  );

  const onSubmit = form.handleSubmit((values) => {
    form.clearErrors("root");
    mutation.mutate({ body: values });
  });

  const { errors, isDirty, isSubmitting } = form.formState;

  return (
    <form onSubmit={onSubmit}>
      <div>
        <label htmlFor="name">Name</label>
        <input id="name" {...form.register("name")} />
        {errors.name && <span className="error">{errors.name.message}</span>}
      </div>

      <div>
        <label htmlFor="email">Email</label>
        <input id="email" type="email" {...form.register("email")} />
        {errors.email && <span className="error">{errors.email.message}</span>}
      </div>

      <div>
        <label htmlFor="bio">Bio</label>
        <textarea id="bio" {...form.register("bio")} />
        {errors.bio && <span className="error">{errors.bio.message}</span>}
      </div>

      <button type="submit" disabled={!isDirty || isSubmitting}>
        {isSubmitting ? "Saving..." : "Save Changes"}
      </button>

      {errors.root && <span className="error">{errors.root.message}</span>}
    </form>
  );
}

许可证

麻省理工学院

版本与发布记录

@beignet/react-hook-form 共发布 65 个版本,首次发布于 2026/05/27;过去 12 个月发布了 65 个版本。

版本发布日期距今
0.0.65latest2026/11/08今天
0.0.642026/11/034 天前
0.0.632026/11/026 天前
0.0.622026/11/017 天前
0.0.612026/11/017 天前
0.0.602026/11/017 天前

关于 @beignet/react-hook-form 的常见问题

@beignet/react-hook-form 是什么?

使用标准Schema支持的 Beignet 重现 Hook Form 集成

如何安装 @beignet/react-hook-form?

在项目目录运行 npm install @beignet/react-hook-form,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18.0.0 || ^19.0.0)、@beignet/core(>=0.0.3 <1.0.0)、react-hook-form(^7.55.0)、@hookform/resolvers(^5.0.0 || ^6.0.0 || ^7.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@beignet/react-hook-form 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@beignet/react-hook-form 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@beignet/react-hook-form 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@beignet/react-hook-form 可以商用吗?

@beignet/react-hook-form 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@beignet/react-hook-form 的下载量有多少?

根据 npm 官方下载统计,@beignet/react-hook-form 在 2026/10/08 – 2026/11/06 这 30 天内被下载 1,927 次,日均约 64 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@beignet/react-hook-form 还在维护吗?

最新版本 0.0.65 发布于 2026/11/08(今天);至今共发布 65 个版本,其中过去 12 个月发布了 65 个;首次发布于 2026/05/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。