服务端操作 (Server Actions)
Next.js 集成了 React Actions,为服务端变更 (server mutations) 提供了内置解决方案。
约定
通过在 Next.js 项目中启用 实验性 serverActions
标志来使用服务端操作功能:
module.exports = {
experimental: {
serverActions: true,
},
}
服务端操作可在以下两种位置定义:
- 使用该操作的组件内部(仅限服务端组件)
- 单独文件中(客户端和服务端组件均可),以实现可复用性。单个文件中可定义多个服务端操作
服务端组件中使用
通过在异步函数体顶部添加 "use server"
指令来创建服务端操作。"use server"
确保该函数仅在服务端执行。
export default function ServerComponent() {
async function myAction() {
'use server'
// ...
}
}
客户端组件中使用
导入方式
在单独文件顶部添加 "use server"
指令创建服务端操作,然后将其导入客户端组件:
'use server'
export async function myAction() {
// ...
}
'use client'
import { myAction } from './actions'
export default function ClientComponent() {
return (
<form action={myAction}>
<button type="submit">加入购物车</button>
</form>
)
}
须知:当使用文件顶层的
"use server"
指令时,该文件下所有导出都将被视为服务端操作。单个文件中可包含多个服务端操作。
属性传递
某些情况下,您可能需要将服务端操作作为属性传递给客户端组件。
<ClientComponent updateItem={updateItem} />
'use client'
export default function ClientComponent({ myAction }) {
return (
<form action={myAction}>
<input type="text" name="name" />
<button type="submit">更新项目</button>
</form>
)
}
参数绑定
使用 bind
方法可以为服务端操作绑定参数。这允许您创建一个已绑定部分参数的新服务端操作,适用于需要传递额外参数的情况。
'use client'
import { updateUser } from './actions'
export function UserProfile({ userId }) {
const updateUserWithId = updateUser.bind(null, userId)
return (
<form action={updateUserWithId}>
<input type="text" name="name" />
<button type="submit">更新用户名称</button>
</form>
)
}
此时 updateUser
服务端操作除了接收表单数据外,还将始终接收 userId
参数:
'use server'
export async function updateUser(userId, formData) {
// ...
}
须知:服务端操作的
.bind
方法在服务端和客户端组件中均可使用,同时支持渐进增强 (Progressive Enhancement)。
调用方式
可通过以下方法调用服务端操作:
- 使用
action
:React 的action
属性允许在<form>
元素上调用服务端操作 - 使用
formAction
:React 的formAction
属性可处理<form>
中的<button>
、<input type="submit">
和<input type="image">
元素 - 使用
startTransition
自定义调用:不使用action
或formAction
的情况下通过startTransition
调用服务端操作,此方法**会禁用渐进增强**功能
渐进增强
渐进增强技术使得 <form>
表单在无 JavaScript 或 JavaScript 禁用时仍能正常工作。即使用户端的表单 JavaScript 尚未加载或加载失败,用户仍可正常提交数据。
React Actions(包括服务端和客户端操作)通过以下两种策略支持渐进增强:
- 若直接将服务端操作传递给
<form>
,即使 JavaScript 被禁用,表单仍可交互 - 若将客户端操作传递给
<form>
,表单在 hydration 完成前仍可交互,但操作会被放入队列等待 hydration 完成后执行。React 会优先处理这些操作,因此响应仍然迅速
两种情况下表单在 hydration 前都保持可交互状态。虽然服务端操作具有不依赖客户端 JavaScript 的额外优势,但您仍可根据需要在客户端操作中组合附加行为,而不会牺牲交互性。
大小限制
默认情况下,发送至服务端操作的请求体最大为 1MB,以防止解析大量数据消耗过多服务器资源。
但您可以通过 serverActionsBodySizeLimit
选项配置此限制。可接受字节数或 bytes 库支持的任何字符串格式,例如 1000
、'500kb'
或 '3mb'
。
module.exports = {
experimental: {
serverActions: true,
serverActionsBodySizeLimit: '2mb',
},
}
扩展资源
以下 React API 文档正在编写中:
"use server"
action
(🚧)formAction
(🚧)useFormStatus
(🚧)useFormState
(🚧)useOptimistic
(🚧)