react server action示例

React Server Action(简称SA)是React 18+推出的核心特性,它允许你直接在客户端触发服务器端的异步逻辑,无需手动写API请求(如fetch/axios),React会自动处理客户端与服务端的通信、数据序列化/反序列化。下面从核心互联方式具体示例关键细节三个维度讲清楚两者的互联逻辑。

一、前置条件

使用Server Action前需满足:

  1. React版本 ≥ 18(推荐19+)
  2. 开启Server Components(SC)环境(Next.js 14+ App Router默认开启,纯React需配置框架如Remix/Redwood)
  3. Server Action必须用 'use server' 指令标记(标识这是运行在服务端的函数)

二、核心互联逻辑(客户端 ↔ 服务端)

Server Action与客户端的互联核心是「客户端触发 → 服务端执行 → 结果返回客户端」,主要有两种触发方式(表单集成、手动触发),下面用Next.js 14+(最主流场景)举例。

方式1:表单集成(最原生/推荐)

这是React官方推荐的方式,表单的action属性直接指向Server Action,React会自动处理:

  • 客户端提交表单时,自动收集FormData并传递给Server Action
  • 自动处理加载状态、提交防抖、页面跳转(可选)
  • 自动返回执行结果/错误到客户端

完整示例(Next.js App Router)

// 1. 定义Server Action(可写在Server Component文件,或单独的actions.ts)
// app/actions.ts(服务端文件,顶部标记'use server')
'use server'

import { revalidatePath } from 'next/cache'

// 定义Server Action:接收客户端传递的FormData,执行服务端逻辑(如操作数据库)
export async function submitUserInfo(formData: FormData) {
  // 从FormData中提取客户端传递的数据
  const name = formData.get('name') as string
  const age = Number(formData.get('age'))

  // 服务端逻辑:验证、操作数据库、调用第三方API等(仅运行在服务端)
  if (!name || age < 0) {
    throw new Error('姓名不能为空,年龄必须为正数') // 抛错会自动返回客户端
  }

  // 模拟数据库操作
  console.log('服务端接收数据:', { name, age }) // 仅在服务端控制台打印

  // 重新验证页面缓存(可选,更新数据后刷新页面数据)
  revalidatePath('/')

  // 返回结果给客户端
  return { success: true, message: `用户${name}信息提交成功` }
}

// 2. 客户端组件(触发Server Action)
// app/page.tsx(客户端组件,用'use client'标记)
'use client'

import { useFormStatus } from 'react-dom'
import { submitUserInfo } from './actions'

// 辅助组件:展示提交状态(加载/成功/失败)
function SubmitButton() {
  const { pending } = useFormStatus() // 获取表单提交状态(React内置)
  return (
    <button type="submit" disabled={pending}>
      {pending ? '提交中...' : '提交信息'}
    </button>
  )
}

// 客户端组件:渲染表单,action指向Server Action
export default function UserForm() {
  // 捕获Server Action的执行结果/错误
  const [submitError, setSubmitError] = useState<string | null>(null)
  const [submitResult, setSubmitResult] = useState<{ success: boolean; message: string } | null>(null)

  // 包装Server Action,处理返回结果/错误
  const handleSubmit = async (formData: FormData) => {
    setSubmitError(null)
    setSubmitResult(null)
    try {
      // 触发Server Action,等待返回结果
      const result = await submitUserInfo(formData)
      setSubmitResult(result)
    } catch (err) {
      // 捕获服务端抛出的错误
      setSubmitError((err as Error).message)
    }
  }

  return (
    <div>
      {/* 表单action指向包装后的处理函数(或直接指向submitUserInfo) */}
      <form action={handleSubmit}>
        <div>
          <label>姓名:</label>
          <input type="text" name="name" required />
        </div>
        <div>
          <label>年龄:</label>
          <input type="number" name="age" min="0" required />
        </div>
        <SubmitButton />
      </form>

      {/* 展示结果/错误 */}
      {submitError && <p style={{ color: 'red' }}>{submitError}</p>}
      {submitResult && <p style={{ color: 'green' }}>{submitResult.message}</p>}
    </div>
  )
}

方式2:手动触发(非表单场景)

如果不是表单提交(比如按钮点击、定时器触发),可以用useActionState Hook手动触发Server Action,实现更灵活的交互。

完整示例

// 1. 还是用上面的submitUserInfo Server Action

// 2. 客户端组件(手动触发)
'use client'

import { useActionState } from 'react'
import { submitUserInfo } from './actions'

// 初始化状态
const initialState = { success: false, message: '', error: '' }

export default function ManualTrigger() {
  // useActionState:绑定Server Action + 初始化状态,返回[状态, 触发函数]
  const [state, dispatch] = useActionState(submitUserInfo, initialState)

  // 手动构造FormData并触发Server Action
  const handleClick = () => {
    const formData = new FormData()
    formData.append('name', '张三')
    formData.append('age', '25')
    dispatch(formData) // 触发Server Action
  }

  return (
    <div>
      <button onClick={handleClick} disabled={state.loading}>
        手动提交
      </button>

      {state.error && <p style={{ color: 'red' }}>{state.error}</p>}
      {state.success && <p style={{ color: 'green' }}>{state.message}</p>}
    </div>
  )
}

三、关键互联细节

  1. 数据传递规则

    • 客户端 → 服务端:支持FormData(推荐)、JSON可序列化数据(对象/数组/字符串/数字,React自动序列化);不支持函数、DOM元素等不可序列化数据。
    • 服务端 → 客户端:返回值需是JSON可序列化数据(对象/数组/基本类型),抛错会被客户端捕获(需用try/catch)。
  2. 状态同步

    • 服务端修改数据后,用revalidatePath/revalidateTag刷新客户端缓存,保证页面数据最新。
    • 客户端用useFormStatus(表单场景)、useActionState(手动场景)获取加载/成功/失败状态。
  3. 跨组件调用

    • Server Action可导出到任意客户端组件,无需担心跨文件调用(React自动处理通信)。
    • 注意:Server Action不能直接在客户端组件的渲染阶段调用(只能在事件处理函数中触发)。

总结

React Server Action与客户端的互联核心要点:

  1. 触发方式:优先用表单action属性(原生集成),非表单场景用useActionState手动触发。
  2. 数据传递:客户端通过FormData/可序列化数据传参,服务端返回可序列化结果,React自动处理通信。
  3. 状态/错误:用useFormStatus/useActionState管理提交状态,try/catch捕获服务端错误,revalidatePath同步页面数据。

这种方式无需手动写API层,大幅简化了客户端与服务端的互联逻辑,是React生态下前后端交互的主流方案。

posted @ 2026-02-13 10:17  卓能文  阅读(37)  评论(0)    收藏  举报