解读 React Router Server Action。
这段代码与之前的 clientAction 非常相似,但有一个核心区别:数据处理逻辑在服务器端执行。这为处理需要安全验证或直接访问数据库等敏感操作提供了保障。
我们同样分两部分来看:action 函数和 Project 组件。
Server action 函数
这个 action 函数被设计为只在服务器上运行。当表单被提交时,React Router 会将请求发送到你的服务器,并由服务器执行这个函数。
jsx
// 这个函数只在服务器上运行
// 它不会被打包进发送给浏览器的 JavaScript 文件中
export async function action({
request,
}: Route.ActionArgs) {
// 1. 在服务器上获取表单数据
let formData = await request.formData();
let title = formData.get("title");
// 2. 在服务器上直接与数据库交互
let project = await fakeDb.updateProject({ title });
// 3. 从服务器返回更新后的数据
return project;
}
代码分步解析:
await request.formData(): 当用户提交表单后,React Router 会向当前页面的 URL 发送一个POST请求。服务器接收到这个请求,这里的代码在服务器环境中解析出表单数据。await fakeDb.updateProject({ title }): 这是最关键的一步。因为这段代码在服务器上运行,所以它可以安全地导入并调用服务器端的模块,比如直接操作数据库的fakeDb。这些敏感的数据库操作逻辑永远不会暴露给用户的浏览器。return project: 函数执行完毕后,会将project数据序列化(通常是转为 JSON),并通过网络响应发送回用户的浏览器。
核心优势:
- 安全性:数据库凭证、私有 API 密钥和核心业务逻辑都保留在服务器上,永远不会发送到客户端,极大地提高了应用的安全性。
- 代码分离 :
action函数及其依赖(如fakeDb)会自动从客户端的 JavaScript 包中移除,减小了浏览器需要下载的文件体积,提升了加载性能。
Project 组件
组件部分的代码与 clientAction 的例子完全一样,但这正是 React Router 设计的巧妙之处。作为开发者,你不需要改变组件的写法,框架会自动处理数据是通过客户端还是服务器端提交的。
jsx
export default function Project({
actionData,
}: Route.ComponentProps) {
return (
<div>
<h1>Project</h1>
{/* A. <Form> 的行为发生了变化 */}
<Form method="post">
<input type="text" name="title" />
<button type="submit">Submit</button>
</Form>
{/* B. 同样接收 action 的返回值并更新 UI */}
{actionData ? (
<p>{actionData.title} updated</p>
) : null}
</div>
);
}
代码分步解析:
A. <Form method="post"> : 在这个场景下,React Router 的 <Form> 组件的行为是:
- 拦截用户的提交事件,阻止页面刷新。
- 创建一个标准的
POST网络请求,将表单数据发送到当前页面的 URL。 - 等待服务器的响应。
B. actionData Prop : 这个 prop 的数据来源变了。它现在接收的是从服务器 响应中返回的数据。当表单提交、服务器上的 action 函数成功执行并返回数据后,React Router 会捕获这个响应,并将数据通过 actionData prop 传递给组件,从而触发 UI 更新。
总结整个流程
这个 Server Action 的流程涉及一次完整的客户端-服务器通信:
- 用户操作:用户在浏览器中输入标题并点击 "Submit"。
- 网络请求 :React Router 的
<Form>组件将表单数据打包,向服务器发起一个POST请求。 - 服务器处理 :服务器接收到请求,调用与该路由匹配的
action函数。 - 数据变更 :
action函数在服务器上安全地执行数据库更新操作。 - 网络响应 :
action函数将更新后的project对象作为响应返回给浏览器。 - UI 更新 :在浏览器端,React Router 接收到这个响应数据,并将其注入到
Project组件的actionDataprop 中。 - 显示反馈 :组件因
actionData变化而重新渲染,无缝地向用户展示更新成功的消息。
对比 clientAction 与 Server action
clientAction:在浏览器中运行,适合执行纯客户端逻辑,如调用公开的第三方 API 或在发送前进行数据校验。反馈更快,因为它不涉及网络往返。- Server
action:在服务器上运行,是处理需要保护的业务逻辑或直接操作后端资源的理想选择。它更安全、更强大。
React Router 允许你在同一个路由中同时定义 clientAction 和 action。在这种情况下,clientAction 会优先执行,这为你实现更复杂的交互模式(如乐观更新)提供了可能。