服务器函数

React 服务器组件

服务器函数用于React 服务器组件

注意:在 2024 年 9 月之前,我们将所有服务器函数称为“服务器操作”。如果服务器函数传递给 action 属性或从 action 内部调用,则它是服务器操作,但并非所有服务器函数都是服务器操作。本文档中的命名已更新,以反映服务器函数可用于多种目的。

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

注意

如何构建对服务器函数的支持?

虽然 React 19 中的服务器函数是稳定的,并且在主要版本之间不会中断,但在 React 服务器组件捆绑器或框架中实现服务器函数的基础 API 不遵循 semver,并且在 React 19.x 的次要版本之间可能会中断。

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

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

服务器函数可以在服务器组件中创建,并作为道具传递给客户端组件,或者可以在客户端组件中导入和使用。

用法

从服务器组件创建服务器函数

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

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

function EmptyNote () {
async function createNoteAction() {
// Server Function
'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 createNote() {
await db.notes.create();
}

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

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

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

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

带有 Action 的服务器函数

可以在客户端的 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>外部调用服务器函数文档。

带有表单 Actions 的服务器函数

服务器函数与 React 19 中的新表单功能一起使用。

您可以将服务器函数传递给表单,以自动将表单提交到服务器。

"use client";

import {updateName} from './actions';

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

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

更多信息,请参见表单中的服务器函数文档。

带有useActionState的服务器函数

您可以使用useActionState调用服务器函数,用于您只需要访问 action 挂起状态和最后返回的响应的常见情况。

"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>
);
}

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

更多信息,请参见useActionState文档。