'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 Functions.
async function addToCart(data) {
'use server';
// ...
}
在客户端上调用服务器函数时,它将向服务器发出网络请求,其中包含传递的任何参数的序列化副本。如果服务器函数返回一个值,则该值将被序列化并返回给客户端。
¥When calling a Server Function on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the Server Function 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 Functions 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 Functions can be passed to Client Components through props. See supported types for serialization. -
要从 客户端代码 导入服务器函数,必须在模块级别使用该指令。
¥To import a Server Functions 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 Functions as untrusted input and authorize any mutations. See security considerations.
-
服务器函数应在 转换 中调用。传递给
<form action>
或formAction
的服务器函数将在转换中自动调用。¥Server Functions should be called in a Transition. Server Functions passed to
<form action>
orformAction
will automatically be called in a transition. -
服务器函数专为更新服务器端状态的突变而设计;不建议将它们用于数据获取。因此,实现服务器函数的框架通常一次处理一个操作,并且没有办法缓存返回值。
¥Server Functions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Functions typically process one action at a time and do not have a way to cache the return value.
安全考虑
¥Security considerations
服务器函数的参数完全由客户端控制。为了安全起见,请始终将它们视为不受信任的输入,并确保适当地验证和转义参数。
¥Arguments to Server Functions 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 Function, make sure to validate that the logged-in user is allowed to perform that action.
可序列化的参数和返回值
¥Serializable arguments and return values
由于客户端代码通过网络调用服务器函数,因此传递的任何参数都需要可序列化。
¥Since client code calls the Server Function over the network, any arguments passed will need to be serializable.
以下是服务器函数参数支持的类型:
¥Here are supported types for Server Function arguments:
-
基础类型
¥Primitives
-
symbol,仅通过
Symbol.for
在全局符号注册表中注册的符号¥symbol, only symbols registered in the global Symbol registry via
Symbol.for
-
包含可序列化值的迭代
¥Iterables containing serializable values
-
¥Map
-
¥Set
-
¥TypedArray and ArrayBuffer
-
¥Date
-
FormData 个实例
¥FormData instances
-
普通 对象:那些用 对象初始值设定项 创建的,具有可序列化的属性
¥Plain objects: those created with object initializers, with serializable properties
-
作为服务器函数的函数
¥Functions that are Server Functions
值得注意的是,这些不受支持:
¥Notably, these are not supported:
-
React 元素,或 JSX
¥React elements, or JSX
-
函数,包括组件函数或任何其他非服务器函数的函数
¥Functions, including component functions or any other function that is not a Server Function
-
作为任何类(除了提到的内置类之外)实例的对象或具有 空原型 的对象
¥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')
-
来自事件处理程序的事件
¥Events from event handlers
对于边界客户端组件,支持的可序列化返回值与 可序列化的属性 相同。
¥Supported serializable return values are the same as serializable props for a boundary Client Component.
用法
¥Usage
表单中的服务器函数
¥Server Functions in forms
服务器函数最常见的用例是调用改变数据的函数。在浏览器上,HTML 表单元素 是用户提交突变的传统方法。借助 React Server Components,React 在 forms 中引入了对服务器函数作为操作的一流支持。
¥The most common use case of Server Functions will be calling 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 Functions as 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 Function passed to a <form>
. When a user submits this form, there is a network request to the server function requestUsername
. When calling a Server Function in a form, React will supply the form’s FormData as the first argument to the Server Function.
通过将服务器函数传递给表单 action
,React 可以 逐步增强 表单。这意味着可以在加载 JavaScript 包之前提交表单。
¥By passing a Server Function 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,同时支持渐进式增强,请使用 useActionState
。
¥To update the UI based on the result of a Server Function while supporting progressive enhancement, use useActionState
.
// 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 { useActionState } from 'react';
import requestUsername from './requestUsername';
function UsernameForm() {
const [state, action] = useActionState(requestUsername, null, 'n/a');
return (
<>
<form action={action}>
<input type="text" name="username" />
<button type="submit">Request</button>
</form>
<p>Last submission request returned: {state}</p>
</>
);
}
请注意,与大多数钩子一样,useActionState
只能在 客户端代码 中调用。
¥Note that like most Hooks, useActionState
can only be called in client code.
在 <form>
之外调用服务器函数
¥Calling a Server Function outside of <form>
服务器函数是公开的服务器端点,可以在客户端代码中的任何位置调用。
¥Server Functions are exposed server endpoints and can be called anywhere in client code.
在 form 之外使用服务器函数时,调用 转换 中的服务器函数,这允许你显示加载指示器、显示 乐观状态更新 和处理意外错误。表单将自动将服务器函数封装在转换中。
¥When using a Server Function outside a form, call the Server Function in a Transition, which allows you to display a loading indicator, show optimistic state updates, and handle unexpected errors. Forms will automatically wrap Server Functions 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;
}
要读取服务器函数返回值,你需要 await
返回的 promise。
¥To read a Server Function return value, you’ll need to await
the promise returned.