服务器操作 - This feature is available in the latest Canary

服务器操作允许客户端组件调用在服务器上执行的异步函数。

注意

如何构建对服务器操作的支持?

虽然 React 19 中的服务器操作是稳定的,并且在主要版本之间不会中断,但在 React 服务器组件捆绑器或框架中用于实现服务器操作的基础 API 不遵循语义化版本控制,并且可能会在 React 19.x 的次要版本之间中断。

为了支持作为捆绑器或框架的服务器操作,我们建议固定到特定的 React 版本,或使用 Canary 版本。 我们将继续与捆绑器和框架合作,以便在将来稳定用于实现服务器操作的 API。

当使用 "use server" 指令定义服务器操作时,您的框架将自动创建对服务器函数的引用,并将该引用传递给客户端组件。 当在客户端调用该函数时,React 将向服务器发送请求以执行该函数,并返回结果。

可以在服务器组件中创建服务器操作,并将其作为 props 传递给客户端组件,或者可以在客户端组件中导入和使用它们。

从服务器组件创建服务器操作

服务器组件可以使用 "use server" 指令定义服务器操作

// Server Component
import Button from './Button';

function EmptyNote () {
async function createNoteAction() {
// Server Action
'use server';

await db.notes.create();
}

return <Button onClick={createNoteAction}/>;
}

当 React 渲染 EmptyNote 服务器组件时,它将创建对 createNoteAction 函数的引用,并将该引用传递给 Button 客户端组件。 当单击该按钮时,React 将使用提供的引用向服务器发送请求,以执行 createNoteAction 函数

"use client";

export default function Button({onClick}) {
console.log(onClick);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
return <button onClick={onClick}>Create Empty Note</button>
}

有关更多信息,请参阅 "use server" 的文档。

从客户端组件导入服务器操作

客户端组件可以从使用 "use server" 指令的文件中导入服务器操作

"use server";

export async function createNoteAction() {
await db.notes.create();
}

当捆绑器构建 EmptyNote 客户端组件时,它将在捆绑包中创建对 createNoteAction 函数的引用。 当单击 button 时,React 将使用提供的引用向服务器发送请求,以执行 createNoteAction 函数

"use client";
import {createNoteAction} from './actions';

function EmptyNote() {
console.log(createNoteAction);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
<button onClick={createNoteAction} />
}

有关更多信息,请参阅 "use server" 的文档。

使用 Actions 组合服务器操作

服务器操作可以与客户端上的 Actions 组合

"use server";

export async function updateName(name) {
if (!name) {
return {error: 'Name is required'};
}
await db.users.updateName(name);
}
"use client";

import {updateName} from './actions';

function UpdateName() {
const [name, setName] = useState('');
const [error, setError] = useState(null);

const [isPending, startTransition] = useTransition();

const submitAction = async () => {
startTransition(async () => {
const {error} = await updateName(name);
if (!error) {
setError(error);
} else {
setName('');
}
})
}

return (
<form action={submitAction}>
<input type="text" name="name" disabled={isPending}/>
{state.error && <span>Failed: {state.error}</span>}
</form>
)
}

这允许您通过将服务器操作包装在客户端上的 Action 中来访问服务器操作的 isPending 状态。

有关更多信息,请参阅 <form> 之外调用服务器操作 的文档

使用服务器操作的表单操作

服务器操作适用于 React 19 中的新表单功能。

您可以将服务器操作传递给表单,以自动将表单提交到服务器

"use client";

import {updateName} from './actions';

function UpdateName() {
return (
<form action={updateName}>
<input type="text" name="name" />
</form>
)
}

当表单提交成功时,React 将自动重置表单。 您可以添加 useActionState 来访问挂起状态、最后响应或支持渐进增强。

有关更多信息,请参阅 表单中的服务器操作 的文档。

使用 useActionState 的服务器操作

对于只需要访问操作待处理状态和上次返回的响应的常见情况,您可以使用 useActionState 来组合服务器操作

"use client";

import {updateName} from './actions';

function UpdateName() {
const [state, submitAction, isPending] = useActionState(updateName, {error: null});

return (
<form action={submitAction}>
<input type="text" name="name" disabled={isPending}/>
{state.error && <span>Failed: {state.error}</span>}
</form>
);
}

在使用服务器操作时,如果使用 useActionState,React 还会自动重放 hydration 完成之前输入的表单提交内容。这意味着用户甚至可以在应用完成 hydration 之前就与您的应用进行交互。

有关详细信息,请参阅 useActionState 的文档。

使用 useActionState 进行渐进增强

服务器操作还支持使用 useActionState 的第三个参数进行渐进增强。

"use client";

import {updateName} from './actions';

function UpdateName() {
const [, submitAction] = useActionState(updateName, null, `/name/update`);

return (
<form action={submitAction}>
...
</form>
);
}

如果在 JavaScript 包加载之前提交了表单,当 permalink 提供给 useActionState 时,React 将重定向到提供的 URL。

有关详细信息,请参阅 useActionState 的文档。