NextJS中文文档 - Updating Data
你可以使用 React 的服务器函数在 Next.js 中更新数据。本页将介绍如何创建和调用服务器函数。
创建服务器函数
服务器函数可以通过使用 use server 指令来定义。你可以将该指令放在异步函数的顶部以将该函数标记为服务器函数,或者放在单独文件的顶部以将该文件的所有导出标记为服务器函数。
ts
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')
// 更新数据
// 重新验证缓存
}js
export async function createPost(formData) {
'use server'
const title = formData.get('title')
const content = formData.get('content')
// 更新数据
// 重新验证缓存
}
export async function deletePost(formData) {
'use server'
const id = formData.get('id')
// 更新数据
// 重新验证缓存
}服务器组件
服务器函数可以通过在函数体顶部添加 "use server" 指令来内联在服务器组件中:
tsx
export default function Page() {
// 服务器操作
async function createPost(formData: FormData) {
'use server'
// ...
}
return <></>
}jsx
export default function Page() {
// 服务器操作
async function createPost(formData) {
'use server'
// ...
}
return <></>
}客户端组件
不能在客户端组件中定义服务器函数。但是,你可以通过从顶部有 "use server" 指令的文件中导入它们来在客户端组件中调用它们:
ts
'use server'
export async function createPost() {}js
'use server'
export async function createPost() {}tsx
'use client'
import { useActionState } 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={async () => action()}>{pending ? <LoadingSpinner /> : '创建文章'}</button>
}jsx
'use client'
import { useActionState } 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={async () => action()}>{pending ? <LoadingSpinner /> : '创建文章'}</button>
}调用服务器函数
有两种主要方式可以调用服务器函数:
表单
React 扩展了 HTML <form> 元素,允许通过 HTML action 属性调用服务器函数。
当在表单中调用时,该函数会自动接收 FormData 对象。你可以使用原生的 FormData 方法提取数据:
tsx
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>
)
}jsx
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>
)
}ts
'use server'
export async function createPost(formData: FormData) {
const title = formData.get('title')
const content = formData.get('content')
// 更新数据
// 重新验证缓存
}js
'use server'
export async function createPost(formData) {
const title = formData.get('title')
const content = formData.get('content')
// 更新数据
// 重新验证缓存
}注意: 当传递给
action属性时,服务器函数也被称为服务器操作。
事件处理程序
你可以在客户端组件中使用 onClick 等事件处理程序来调用服务器函数。
tsx
'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>
</>
)
}jsx
'use client'
import { incrementLike } from './actions'
import { useState } from 'react'
export default function LikeButton({ initialLikes }) {
const [likes, setLikes] = useState(initialLikes)
return (
<>
<p>总点赞数:{likes}</p>
<button
onClick={async () => {
const updatedLikes = await incrementLike()
setLikes(updatedLikes)
}}
>
点赞
</button>
</>
)
}示例
显示等待状态
在执行服务器函数时,你可以使用 React 的 useActionState hook 显示加载指示器。这个 hook 返回一个 pending 布尔值:
tsx
'use client'
import { useActionState } 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={async () => action()}>{pending ? <LoadingSpinner /> : '创建文章'}</button>
}jsx
'use client'
import { useActionState } 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={async () => action()}>{pending ? <LoadingSpinner /> : '创建文章'}</button>
}重新验证缓存
执行更新后,你可以通过在服务器函数中调用 revalidatePath 或 revalidateTag 来重新验证 Next.js 缓存并显示更新后的数据:
ts
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
'use server'
// 更新数据
// ...
revalidatePath('/posts')
}js
import { revalidatePath } from 'next/cache'
export async function createPost(formData) {
'use server'
// 更新数据
// ...
revalidatePath('/posts')
}重定向
在执行更新后,你可能想要将用户重定向到不同的页面。你可以通过在服务器函数中调用 redirect 来实现这一点:
ts
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// 更新数据
// ...
redirect('/posts')
}js
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData) {
// 更新数据
// ...
redirect('/posts')
}

