如何在 Next.js 中构建联系表单(无需后端)

发布: (2026年3月26日 GMT+8 09:30)
6 分钟阅读
原文: Dev.to

Source: Dev.to

封面图片:如何在 Next.js 中构建联系表单(无需构建后端)

Long N.

选项速览

当你搜索 “Next.js contact form” 时,通常会看到三种方法:

  1. Route Handler + email API (Resend, SendGrid, etc.) – 完全控制,但所有东西都由你自己负责。
  2. Server Actions – 更清晰的开发体验,但你仍需自行处理邮件 + 垃圾邮件。
  3. Form‑backend service – 将数据发送到托管的端点;它会处理存储 + 邮件。

对于大多数项目——着陆页、SaaS 网站、静态应用——选项 3 是最快的路径。本指南将详细介绍这种方法。

最简版本:仅 HTML

如果你不需要加载状态或交互功能,可以使用纯 HTML 表单,完全不使用 JavaScript:

<form action="https://formtorch.com/f/YOUR_FORM_ID" method="POST">
  <input type="text" name="name" placeholder="Name" required />
  <input type="email" name="email" placeholder="Email" required />
  <textarea name="message" placeholder="Message" required></textarea>
  <button type="submit">Send message</button>
</form>

这已经是一个可用的表单。浏览器会处理提交,提交后会自动重定向。

重定向到你自己的页面

<form action="/thank-you" method="POST">
  <!-- fields -->
</form>

对于许多使用场景来说,这已经足够。但 React 应用通常希望实现更具交互性的功能。

合适的 React 联系表单

以下是一个具备加载、成功和错误状态的可直接投入生产的组件:

"use client";

import { useState } from "react";

type FormState = "idle" | "loading" | "success" | "error";

export function ContactForm() {
  const [state, setState] = useState<FormState>("idle");

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setState("loading");

    try {
      const data = new FormData(e.currentTarget);

      const res = await fetch("https://formtorch.com/f/YOUR_FORM_ID", {
        method: "POST",
        headers: { "X-Requested-With": "XMLHttpRequest" },
        body: data,
      });

      if (!res.ok) throw new Error();
      setState("success");
    } catch {
      setState("error");
    }
  }

  if (state === "success") {
    return (
      <div>
        <h3>Message sent.</h3>
        <p>Thanks for reaching out. I’ll get back to you soon.</p>
      </div>
    );
  }

  return (
    <form onSubmit={handleSubmit} noValidate>
      <label>
        Name
        <input type="text" name="name" required />
      </label>

      <label>
        Email
        <input type="email" name="email" required />
      </label>

      <label>
        Message
        <textarea name="message" required></textarea>
      </label>

      {state === "error" && <p>Something went wrong. Try again.</p>}

      <button type="submit" disabled={state === "loading"}>
        {state === "loading" ? "Sending…" : "Send message"}
      </button>
    </form>
  );
}

为什么这样做效果好

  • 使用 FormData 而非 JSON: 自动捕获所有字段(包括文件)。
  • X-Requested-With 请求头: 确保返回的是 JSON 而不是 HTML 重定向。
  • 加载中 + 按钮禁用: 防止重复提交。

添加验证

您可以在不更改结构的情况下添加客户端验证:

function validate(data: FormData) {
  const errors: Record<string, string> = {};

  if (!data.get("name")) errors.name = "Name is required";

  const email = String(data.get("email") ?? "");
  if (!email) errors.email = "Email is required";
  else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
    errors.email = "Invalid email";

  if (!data.get("message")) errors.message = "Message is required";

  return errors;
}

<form> 元素上添加 noValidate 以禁用浏览器的原生 UI,并自行渲染错误。

使用 react-hook-form

对于更复杂的表单,react-hook-form 简化了状态管理:

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

export function ContactForm() {
  const { register, handleSubmit, formState } = useForm();

  async function onSubmit(data: any) {
    const formData = new FormData();
    Object.entries(data).forEach(([k, v]) => formData.append(k, String(v)));

    await fetch("https://formtorch.com/f/YOUR_FORM_ID", {
      method: "POST",
      headers: { "X-Requested-With": "XMLHttpRequest" },
      body: formData,
    });
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)} noValidate>
      <input {...register("name")} placeholder="Name" required />
      <input {...register("email")} type="email" placeholder="Email" required />
      <textarea {...register("message")} placeholder="Message" required></textarea>

      <button type="submit" disabled={formState.isSubmitting}>
        {formState.isSubmitting ? "Sending…" : "Send"}
      </button>
    </form>
  );
}

使用像 Formtorch 这样的托管表单后端,你可以在几分钟内搭建出功能完整的联系表单——无需自定义 API、无需服务器端邮件处理,也不需要维护额外的基础设施。祝编码愉快!

关于垃圾信息怎么办?

每个公开的表单都会收到垃圾信息。

常见做法

  • CAPTCHA(用户体验差)
  • 蜜罐
  • 限流
  • 垃圾信息检测

一个简单的蜜罐字段:

<input type="text" name="website" style="display:none" tabindex="-1" autocomplete="off" />

机器人会填写它。人类不会。

要点

你不需要专门搭建后端来发送联系表单的邮件。

实际设置

  • 简单页面 → HTML 表单
  • React 应用 → fetch + FormData
  • 复杂表单 → react-hook-form

其他的都只是管道工作。

可选:完全跳过后端

如果你不想处理电子邮件 API、垃圾邮件过滤或存储提交数据,可以使用托管的表单后端。

例如,Formtorch 为你提供:

  • 可直接使用的端点
  • 电子邮件通知
  • 内置垃圾邮件过滤

这样你的表单就可以在没有任何服务器代码的情况下工作。

如果你想尝试:

👉 Formtorch

无论哪种方式,一旦你了解了整个流程,联系表单就不再是“设置的麻烦”,而是一个已经解决的问题。

0 浏览
Back to Blog

相关文章

阅读更多 »