服务端操作 (Server Actions)

Next.js 集成了 React Actions,为服务端变更 (server mutations) 提供了内置解决方案。

约定

通过在 Next.js 项目中启用 实验性 serverActions 标志来使用服务端操作功能:

next.config.js
module.exports = {
  experimental: {
    serverActions: true,
  },
}

服务端操作可在以下两种位置定义:

  • 使用该操作的组件内部(仅限服务端组件)
  • 单独文件中(客户端和服务端组件均可),以实现可复用性。单个文件中可定义多个服务端操作

服务端组件中使用

通过在异步函数体顶部添加 "use server" 指令来创建服务端操作。"use server" 确保该函数仅在服务端执行。

此函数应具有可序列化参数可序列化返回值

app/page.js
export default function ServerComponent() {
  async function myAction() {
    'use server'
    // ...
  }
}

客户端组件中使用

导入方式

在单独文件顶部添加 "use server" 指令创建服务端操作,然后将其导入客户端组件:

app/actions.js
'use server'

export async function myAction() {
  // ...
}
app/client-component.jsx
'use client'

import { myAction } from './actions'

export default function ClientComponent() {
  return (
    <form action={myAction}>
      <button type="submit">加入购物车</button>
    </form>
  )
}

须知:当使用文件顶层的 "use server" 指令时,该文件下所有导出都将被视为服务端操作。单个文件中可包含多个服务端操作。

属性传递

某些情况下,您可能需要将服务端操作作为属性传递给客户端组件。

<ClientComponent updateItem={updateItem} />
app/client-component.jsx
'use client'

export default function ClientComponent({ myAction }) {
  return (
    <form action={myAction}>
      <input type="text" name="name" />
      <button type="submit">更新项目</button>
    </form>
  )
}

参数绑定

使用 bind 方法可以为服务端操作绑定参数。这允许您创建一个已绑定部分参数的新服务端操作,适用于需要传递额外参数的情况。

app/client-component.jsx
'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 参数:

app/actions.js
'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 自定义调用:不使用 actionformAction 的情况下通过 startTransition 调用服务端操作,此方法**会禁用渐进增强**功能

渐进增强

渐进增强技术使得 <form> 表单在无 JavaScript 或 JavaScript 禁用时仍能正常工作。即使用户端的表单 JavaScript 尚未加载或加载失败,用户仍可正常提交数据。

React Actions(包括服务端和客户端操作)通过以下两种策略支持渐进增强:

  • 若直接将服务端操作传递给 <form>,即使 JavaScript 被禁用,表单仍可交互
  • 若将客户端操作传递给 <form>,表单在 hydration 完成前仍可交互,但操作会被放入队列等待 hydration 完成后执行。React 会优先处理这些操作,因此响应仍然迅速

两种情况下表单在 hydration 前都保持可交互状态。虽然服务端操作具有不依赖客户端 JavaScript 的额外优势,但您仍可根据需要在客户端操作中组合附加行为,而不会牺牲交互性。

大小限制

默认情况下,发送至服务端操作的请求体最大为 1MB,以防止解析大量数据消耗过多服务器资源。

但您可以通过 serverActionsBodySizeLimit 选项配置此限制。可接受字节数或 bytes 库支持的任何字符串格式,例如 1000'500kb''3mb'

next.config.js
module.exports = {
  experimental: {
    serverActions: true,
    serverActionsBodySizeLimit: '2mb',
  },
}

扩展资源

以下 React API 文档正在编写中:

  • "use server"
  • action (🚧)
  • formAction (🚧)
  • useFormStatus (🚧)
  • useFormState (🚧)
  • useOptimistic (🚧)

On this page