'use server' - This feature is available in the latest Canary

Canary

仅当你是 使用 React 服务器组件 或构建与它们兼容的库时才需要 'use server'

¥'use server' is needed only if you’re using React Server Components or building a library compatible with them.

'use server' 标记可以从客户端代码调用的服务器端函数。

¥'use server' marks server-side functions that can be called from client-side code.


参考

¥Reference

'use server'

在异步函数体的顶部添加 'use server' 以将该函数标记为可由客户端调用。我们将这些功能称为服务器操作。

¥Add 'use server' at the top of an async function body to mark the function as callable by the client. We call these functions Server Actions.

async function addToCart(data) {
'use server';
// ...
}

当在客户端上调用服务器操作时,它将向服务器发出网络请求,其中包括传递的任何参数的序列化副本。如果服务器操作返回一个值,该值将被序列化并返回给客户端。

¥When calling a Server Action on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the Server Action returns a value, that value will be serialized and returned to the client.

你可以将该指令添加到文件顶部,将该文件中的所有导出标记为可以在任何地方使用的服务器操作,包括在客户端代码中导入,而不是单独使用 'use server' 标记函数。

¥Instead of individually marking functions with 'use server', you can add the directive to the top of a file to mark all exports within that file as Server Actions that can be used anywhere, including imported in client code.

注意事项

¥Caveats

  • 'use server' 必须位于其函数或模块的最开头;高于任何其他代码,包括导入(指令上方的注释都可以)。它们必须用单引号或双引号编写,而不是反引号。

    ¥'use server' must be at the very beginning of their function or module; above any other code including imports (comments above directives are OK). They must be written with single or double quotes, not backticks.

  • 'use server' 只能在服务器端文件中使用。生成的服务器操作可以通过属性传递给客户端组件。请参阅支持的 序列化类型

    ¥'use server' can only be used in server-side files. The resulting Server Actions can be passed to Client Components through props. See supported types for serialization.

  • 要从 客户端代码 导入服务器操作,必须在模块级别使用该指令。

    ¥To import a Server Action from client code, the directive must be used on a module level.

  • 由于底层网络调用始终是异步的,因此 'use server' 只能用于异步函数。

    ¥Because the underlying network calls are always asynchronous, 'use server' can only be used on async functions.

  • 始终将服务器操作的参数视为不受信任的输入并授权任何更改。参见 安全考虑

    ¥Always treat arguments to Server Actions as untrusted input and authorize any mutations. See security considerations.

  • 应在 transition 中调用服务器操作。传递到 <form action>formAction 的服务器操作将在转换中自动调用。

    ¥Server Actions should be called in a transition. Server Actions passed to <form action> or formAction will automatically be called in a transition.

  • 服务器操作是为更新服务器端状态的突变而设计的;不建议将它们用于数据获取。因此,实现服务器操作的框架通常一次处理一个操作,并且没有办法缓存返回值。

    ¥Server Actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Actions typically process one action at a time and do not have a way to cache the return value.

安全考虑

¥Security considerations

服务器操作的参数完全由客户端控制。为了安全起见,请始终将它们视为不受信任的输入,并确保适当地验证和转义参数。

¥Arguments to Server Actions are fully client-controlled. For security, always treat them as untrusted input, and make sure to validate and escape arguments as appropriate.

在任何服务器操作中,请确保验证已登录的用户是否有权执行该操作。

¥In any Server Action, make sure to validate that the logged-in user is allowed to perform that action.

开发中

为了防止从服务器操作发送敏感数据,有实验性的污点 API 可以防止将唯一值和对象传递给客户端代码。

¥To prevent sending sensitive data from a Server Action, there are experimental taint APIs to prevent unique values and objects from being passed to client code.

参见 experimental_taintUniqueValueexperimental_taintObjectReference

¥See experimental_taintUniqueValue and experimental_taintObjectReference.

可序列化的参数和返回值

¥Serializable arguments and return values

当客户端代码通过网络调用服务器操作时,传递的任何参数都需要可序列化。

¥As client code calls the Server Action over the network, any arguments passed will need to be serializable.

以下是服务器操作参数支持的类型:

¥Here are supported types for Server Action arguments:

值得注意的是,这些不受支持:

¥Notably, these are not supported:

  • 反应元素,或 JSX

    ¥React elements, or JSX

  • 函数,包括组件函数或任何其他非服务器操作的函数

    ¥Functions, including component functions or any other function that is not a Server Action

  • ¥Classes

  • 作为任何类(除了提到的内置类之外)实例的对象或具有 空原型 的对象

    ¥Objects that are instances of any class (other than the built-ins mentioned) or objects with a null prototype

  • 未在全局注册的符号,例如。Symbol('my new symbol')

    ¥Symbols not registered globally, ex. Symbol('my new symbol')

对于边界客户端组件,支持的可序列化返回值与 可序列化的属性 相同。

¥Supported serializable return values are the same as serializable props for a boundary Client Component.

用法

¥Usage

表单中的服务器操作

¥Server Actions in forms

服务器操作最常见的用例是调用改变数据的服务器函数。在浏览器上,HTML 表单元素 是用户提交突变的传统方法。通过 React Server Components,React 在 forms 中引入了对服务器操作的一流支持。

¥The most common use case of Server Actions will be calling server functions that mutate data. On the browser, the HTML form element is the traditional approach for a user to submit a mutation. With React Server Components, React introduces first-class support for Server Actions in forms.

这是一个允许用户请求用户名的表单。

¥Here is a form that allows a user to request a username.

// App.js

async function requestUsername(formData) {
'use server';
const username = formData.get('username');
// ...
}

export default function App() {
return (
<form action={requestUsername}>
<input type="text" name="username" />
<button type="submit">Request</button>
</form>
);
}

在此示例中,requestUsername 是传递给 <form> 的服务器操作。当用户提交此表单时,就会向服务器功能 requestUsername 发出网络请求。当在表单中调用服务器操作时,React 会将表单的 FormData 作为服务器操作的第一个参数。

¥In this example requestUsername is a Server Action passed to a <form>. When a user submits this form, there is a network request to the server function requestUsername. When calling a Server Action in a form, React will supply the form’s FormData as the first argument to the Server Action.

通过将服务器操作传递给表单 action,React 可以对该表单进行 逐步增强。这意味着可以在加载 JavaScript 包之前提交表单。

¥By passing a Server Action to the form action, React can progressively enhance the form. This means that forms can be submitted before the JavaScript bundle is loaded.

处理表单中的返回值

¥Handling return values in forms

在用户名请求表单中,用户名可能不可用。requestUsername 应该告诉我们它是否失败。

¥In the username request form, there might be the chance that a username is not available. requestUsername should tell us if it fails or not.

要根据服务器操作的结果更新 UI,同时支持渐进增强,请使用 useFormState

¥To update the UI based on the result of a Server Action while supporting progressive enhancement, use useFormState.

// requestUsername.js
'use server';

export default async function requestUsername(formData) {
const username = formData.get('username');
if (canRequest(username)) {
// ...
return 'successful';
}
return 'failed';
}
// UsernameForm.js
'use client';

import { useFormState } from 'react-dom';
import requestUsername from './requestUsername';

function UsernameForm() {
const [returnValue, action] = useFormState(requestUsername, 'n/a');

return (
<>
<form action={action}>
<input type="text" name="username" />
<button type="submit">Request</button>
</form>
<p>Last submission request returned: {returnValue}</p>
</>
);
}

请注意,与大多数钩子一样,useFormState 只能在 客户端代码 中调用。

¥Note that like most Hooks, useFormState can only be called in client code.

调用 <form> 外部的服务器操作

¥Calling a Server Action outside of <form>

服务器操作是公开的服务器端点,可以在客户端代码中的任何位置调用。

¥Server Actions are exposed server endpoints and can be called anywhere in client code.

form 外部使用服务器操作时,调用 transition 中的服务器操作,这允许你显示加载指示器、显示 乐观状态更新 并处理意外错误。表单将自动将服务器操作封装在转换中。

¥When using a Server Action outside of a form, call the Server Action in a transition, which allows you to display a loading indicator, show optimistic state updates, and handle unexpected errors. Forms will automatically wrap Server Actions in transitions.

import incrementLike from './actions';
import { useState, useTransition } from 'react';

function LikeButton() {
const [isPending, startTransition] = useTransition();
const [likeCount, setLikeCount] = useState(0);

const onClick = () => {
startTransition(async () => {
const currentCount = await incrementLike();
setLikeCount(currentCount);
});
};

return (
<>
<p>Total Likes: {likeCount}</p>
<button onClick={onClick} disabled={isPending}>Like</button>;
</>
);
}
// actions.js
'use server';

let likeCount = 0;
export default async function incrementLike() {
likeCount++;
return likeCount;
}

要读取服务器操作返回值,你需要对返回的 promise 进行 await

¥To read a Server Action return value, you’ll need to await the promise returned.


React 中文网 - 粤ICP备13048890号