本文最后更新于6 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
一、Next.js Server Action 表单绑定方式
两种方式对比
1. ❌ 错误方式(原代码)
<form className="flex-1 flex flex-col min-w-64">
<Input name="email" />
<SubmitButton formAction={signInAction}>Sign in</SubmitButton>
</form>
formAction 属性放在 button 上,只有在纯客户端表单中才有效。但在 Next.js 服务器组件渲染的页面中,这种方式可能无法正确绑定。
2. ✅ 正确方式(修改后)
<form className="flex-1 flex flex-col min-w-64" action={signInAction}>
<Input name="email" />
<SubmitButton>Sign in</SubmitButton>
</form>
action 属性放在 form 标签上,这是 HTML 标准表单提交方式,更可靠。
为什么这样修改?
| 特性 | formAction (button 上) | action (form 上) |
|---|---|---|
| HTML 标准 | ✅ 支持 | ✅ 支持 |
| Next.js 服务器组件 | ⚠️ 可能失效 | ✅ 完全支持 |
| 多按钮表单 | ✅ 不同按钮提交不同动作 | ❌ 整个表单只能一个 action |
| 简单单提交表单 | ✅ 可用 | ✅ 推荐 |
本项目的情况
这个登录/注册表单只有一个提交按钮,所以把 action 放在 form 标签上是最简单可靠的方式:
// signInAction 和 signUpAction 都是 Server Action
export const signInAction = async (formData: FormData) => {
const email = formData.get("email") as string;
const password = formData.get("password") as string;
// ... 处理逻辑
};
当用户点击提交按钮时:
- 表单数据通过 POST 提交到
action指定的 Server Action - Server Action 在服务器端执行(访问数据库、调用 API 等)
- 执行
redirect()跳转到目标页面
这就是 Next.js App Router 推荐的表单提交模式。
二、项目语法问题
👉.ts = 纯 TypeScript 文件 写逻辑
👉 .tsx = 可以写 JSX(React 代码)的 TypeScript 文件 写界面
👉 优先用 export const(命名导出)
👉 只有在“明确唯一入口”的场景才用 export default
三、核心区别(本质)
| 对比点 | export default | export const |
|---|---|---|
| 数量 | 只能 1 个 | 可以多个 |
| 导入方式 | 自定义名字 | 必须同名 |
| 可读性 | ❌ 不直观 | ✅ 很清晰 |
| 重构友好 | ❌ 差 | ✅ 好 |
| 推荐程度 | ⭐⭐ | ⭐⭐⭐⭐ |
✅ 1. 可读性更强
// utils.ts
export const add = () => {};
export const sub = () => {};
导入时:
import { add, sub } from "./utils";
👉 一眼知道用了哪些函数 👍
❌ default 的问题
export default function add() {}
import abc from "./utils";
👉 abc 是啥??完全看不出来 😅
✅ 2. 更利于团队协作
多人开发时:
👉 命名导出强制统一名字
👉 不会出现:
import fn1 from "./utils";
import fn2 from "./utils";
这种混乱情况
✅ 3. 更好重构(非常关键)
IDE(比如 VSCode):
👉 对命名导出支持更好(自动重命名、跳转)
👉 只在这些场景用(记住这几个就够了)
✅ 1. React / Next.js 页面
export default function Page() {
return <div>首页</div>;
}
👉 框架要求必须 default
✅ 2. 单一核心模块
比如:
export default class UserService {}
👉 这个文件就干一件事
✅ 3. UI组件(有争议)
export default function Button() {}
👉 有些团队允许这样写
1. 工具函数 → 一律 export const
2. hooks → export const
3. 常量 / 类型 → export const / export type
4. 页面 → export default(必须)
5. 单一类 / 服务 → 可用 default
❌ 不推荐写法
// utils.ts
export default function add() {}
import xxx from "./utils"; // ❌ 不清晰
✅ 推荐写法
// utils.ts
export const add = () => {};
import { add } from "./utils"; // ✅ 清晰
你可以这样总结:
在实际项目中我更倾向使用
export const,因为它具备更好的可读性、可维护性和重构友好性,特别是在多人协作时可以避免命名混乱。
只有在明确单一导出的场景,比如 Next.js 页面或模块入口时,我才会使用export default。
👉 Tree Shaking(打包优化)
export const👉 更容易被优化掉未使用代码 ✅export default👉 有时不容易优化 ❌
👉 开发优先用 export const,框架要求才用 export default
