表单验证

表单验证

本指南将逐步介绍一个简单的注册表单实现。您可能希望将这些概念与第三方验证库和错误组件结合使用,但本指南仅关注 React Router 中的移动部件。

1. 设置

我们将从创建一个带有表单的基本注册路由开始。

import {
  type RouteConfig,
  route,
} from "@react-router/dev/routes";

export default [
  route("signup", "signup.tsx"),
] satisfies RouteConfig;
import type { Route } from "./+types/signup";
import { useFetcher } from "react-router";

export default function Signup(_: Route.ComponentProps) {
  let fetcher = useFetcher();
  return (
    <fetcher.Form method="post">
      <p>
        <input type="email" name="email" />
      </p>

      <p>
        <input type="password" name="password" />
      </p>

      <button type="submit">Sign Up</button>
    </fetcher.Form>
  );
}

2. 定义操作

在此步骤中,我们将在与 Signup 组件相同的文件中定义一个服务器 action。请注意,此处的目标是提供所涉及机制的广泛概述,而不是深入探讨表单验证规则或错误对象结构。我们将使用基本的电子邮件和密码检查来演示核心概念。

import type { Route } from "./+types/signup";
import { redirect, useFetcher, data } from "react-router";

export default function Signup(_: Route.ComponentProps) {
  // omitted for brevity
}

export async function action({
  request,
}: Route.ActionArgs) {
  const formData = await request.formData();
  const email = String(formData.get("email"));
  const password = String(formData.get("password"));

  const errors = {};

  if (!email.includes("@")) {
    errors.email = "Invalid email address";
  }

  if (password.length < 12) {
    errors.password =
      "Password should be at least 12 characters";
  }

  if (Object.keys(errors).length > 0) {
    return data({ errors }, { status: 400 });
  }

  // Redirect to dashboard if validation is successful
  return redirect("/dashboard");
}

如果发现任何验证错误,则会从 action 返回到 fetcher。这是我们向 UI 发出信号以指示需要更正某些内容的方式,否则用户将被重定向到仪表板。

请注意 data({ errors }, { status: 400 }) 调用。设置 400 状态是 Web 标准的方式,用于向客户端发出存在验证错误(错误请求)的信号。在 React Router 中,只有 200 状态代码会触发页面数据重新验证,因此 400 会阻止这种情况。

3. 显示验证错误

最后,我们将修改 Signup 组件以显示(如果有)来自 fetcher.data 的验证错误。

export default function Signup(_: Route.ComponentProps) {
  let fetcher = useFetcher();
  let errors = fetcher.data?.errors;
  return (
    <fetcher.Form method="post">
      <p>
        <input type="email" name="email" />
        {errors?.email ? <em>{errors.email}</em> : null}
      </p>

      <p>
        <input type="password" name="password" />
        {errors?.password ? (
          <em>{errors.password}</em>
        ) : null}
      </p>

      <button type="submit">Sign Up</button>
    </fetcher.Form>
  );
}
文档和示例 CC 4.0