如何更新数据

您可以使用 React 的 服务端函数 (Server Functions) 在 Next.js 中更新数据。本页将介绍如何创建调用服务端函数。

服务端函数

服务端函数是在服务器端执行的异步函数。由于它们是通过客户端发起的网络请求调用的,因此本质上是异步的。当作为 action 的一部分被调用时,它们也被称为服务端操作 (Server Actions)

按照约定,action 是传递给 startTransition 的异步函数。服务端函数在以下情况下会自动被 startTransition 包裹:

  • 通过 action 属性传递给 <form>
  • 通过 formAction 属性传递给 <button>
  • 传递给 useActionState

创建服务端函数

可以通过使用 use server 指令来定义服务端函数。您可以将该指令放在异步函数的顶部以将其标记为服务端函数,或者放在单独文件的顶部以标记该文件的所有导出。

export async function createPost(formData: FormData) {
  'use server'
  const title = formData.get('title')
  const content = formData.get('content')

  // 更新数据
  // 重新验证缓存
}

export async function deletePost(formData: FormData) {
  'use server'
  const id = formData.get('id')

  // 更新数据
  // 重新验证缓存
}

服务端组件

可以通过在函数体顶部添加 "use server" 指令,在服务端组件中内联定义服务端函数:

export default function Page() {
  // 服务端操作
  async function createPost(formData: FormData) {
    'use server'
    // ...
  }

  return <></>
}

客户端组件

无法在客户端组件中定义服务端函数。但您可以通过从顶部带有 "use server" 指令的文件导入它们,在客户端组件中调用这些函数:

'use server'

export async function createPost() {}

调用服务端函数

有两种主要方式可以调用服务端函数:

  1. 服务端和客户端组件中的表单
  2. 客户端组件中的事件处理程序

表单

React 扩展了 HTML <form> 元素,允许通过 HTML action 属性调用服务端函数。

在表单中调用时,函数会自动接收 FormData 对象。您可以使用原生 FormData 方法提取数据:

import { createPost } from '@/app/actions'

export function Form() {
  return (
    <form action={createPost}>
      <input type="text" name="title" />
      <input type="text" name="content" />
      <button type="submit">创建</button>
    </form>
  )
}

须知: 当传递给 action 属性时,服务端函数也被称为_服务端操作 (Server Actions)_。

事件处理程序

您可以在客户端组件中使用 onClick 等事件处理程序调用服务端函数。

'use client'

import { incrementLike } from './actions'
import { useState } from 'react'

export default function LikeButton({ initialLikes }: { initialLikes: number }) {
  const [likes, setLikes] = useState(initialLikes)

  return (
    <>
      <p>总点赞数: {likes}</p>
      <button
        onClick={async () => {
          const updatedLikes = await incrementLike()
          setLikes(updatedLikes)
        }}
      >
        点赞
      </button>
    </>
  )
}

示例

显示等待状态

在执行服务端函数时,您可以使用 React 的 useActionState 钩子显示加载指示器。该钩子会返回一个 pending 布尔值:

'use client'

import { useActionState, startTransition } from 'react'
import { createPost } from '@/app/actions'
import { LoadingSpinner } from '@/app/ui/loading-spinner'

export function Button() {
  const [state, action, pending] = useActionState(createPost, false)

  return (
    <button onClick={() => startTransition(action)}>
      {pending ? <LoadingSpinner /> : '创建文章'}
    </button>
  )
}

重新验证缓存

执行更新后,您可以通过在服务端函数中调用 revalidatePathrevalidateTag 来重新验证 Next.js 缓存并显示更新后的数据:

import { revalidatePath } from 'next/cache'

export async function createPost(formData: FormData) {
  'use server'
  // 更新数据
  // ...

  revalidatePath('/posts')
}

重定向

您可能希望在执行更新后将用户重定向到其他页面。可以通过在服务端函数中调用 redirect 来实现:

'use server'

import { redirect } from 'next/navigation'

export async function createPost(formData: FormData) {
  // 更新数据
  // ...

  redirect('/posts')
}

On this page