数据突变通过路由操作完成。当操作完成后,页面上所有的加载器数据都会被重新验证,以保持 UI 与数据同步,而无需编写任何代码来实现。
使用 action
定义的路由操作仅在服务器上调用,而使用 clientAction
定义的操作则在浏览器中运行。
客户端操作仅在浏览器中运行,并且当同时定义了服务器操作时,客户端操作优先。
// route('/projects/:projectId', './project.tsx')
import type { Route } from "./+types/project";
import { Form } from "react-router";
import { someApi } from "./api";
export async function clientAction({
request,
}: Route.ClientActionArgs) {
let formData = await request.formData();
let title = formData.get("title");
let project = await someApi.updateProject({ title });
return project;
}
export default function Project({
actionData,
}: Route.ComponentProps) {
return (
<div>
<h1>Project</h1>
<Form method="post">
<input type="text" name="title" />
<button type="submit">Submit</button>
</Form>
{actionData ? (
<p>{actionData.title} updated</p>
) : null}
</div>
);
}
服务器操作仅在服务器上运行,并会从客户端捆绑包中移除。
// route('/projects/:projectId', './project.tsx')
import type { Route } from "./+types/project";
import { Form } from "react-router";
import { fakeDb } from "../db";
export async function action({
request,
}: Route.ActionArgs) {
let formData = await request.formData();
let title = formData.get("title");
let project = await fakeDb.updateProject({ title });
return project;
}
export default function Project({
actionData,
}: Route.ComponentProps) {
return (
<div>
<h1>Project</h1>
<Form method="post">
<input type="text" name="title" />
<button type="submit">Submit</button>
</Form>
{actionData ? (
<p>{actionData.title} updated</p>
) : null}
</div>
);
}
操作通过 <Form>
声明式调用,或通过 useSubmit
(或 <fetcher.Form>
和 fetcher.submit
)命令式调用,方法是引用路由的路径和 "post" 方法。
import { Form } from "react-router";
function SomeComponent() {
return (
<Form action="/projects/123" method="post">
<input type="text" name="title" />
<button type="submit">Submit</button>
</Form>
);
}
这将导致一次导航,并且一个新的条目将被添加到浏览器历史记录中。
您可以使用 useSubmit
以命令式方式将表单数据提交到一个操作。
import { useCallback } from "react";
import { useSubmit } from "react-router";
import { useFakeTimer } from "fake-lib";
function useQuizTimer() {
let submit = useSubmit();
let cb = useCallback(() => {
submit(
{ quizTimedOut: true },
{ action: "/end-quiz", method: "post" },
);
}, []);
let tenMinutes = 10 * 60 * 1000;
useFakeTimer(tenMinutes, cb);
}
这将导致一次导航,并且一个新的条目将被添加到浏览器历史记录中。
Fetcher 允许您向操作(和加载器)提交数据,而不会引起导航(即浏览器历史记录中不会有新条目)。
import { useFetcher } from "react-router";
function Task() {
let fetcher = useFetcher();
let busy = fetcher.state !== "idle";
return (
<fetcher.Form method="post" action="/update-task/123">
<input type="text" name="title" />
<button type="submit">
{busy ? "Saving..." : "Save"}
</button>
</fetcher.Form>
);
}
它们还有一个命令式的 submit
方法。
fetcher.submit(
{ title: "New Title" },
{ action: "/update-task/123", method: "post" },
);
有关更多信息,请参阅使用 Fetcher指南。
下一步: 导航