操作
本页内容

Action

简介

数据修改通过 Route action 完成。当 action 完成时,页面上的所有 loader 数据都会被重新验证,以使您的 UI 与数据保持同步,而无需编写任何代码来实现。

使用 action 定义的 Route action 只会在服务器上调用,而使用 clientAction 定义的 action 则在浏览器中运行。

客户端 Action

客户端 action 只在浏览器中运行,并且当同时定义了服务器 action 时,客户端 action 会优先执行。

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

服务器 Action

服务器 action 只在服务器上运行,并且会从客户端打包文件中移除。

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

调用 Action

Action 可以通过 <Form> 声明式地调用,也可以通过 useSubmit(或 <fetcher.Form>fetcher.submit)命令式地调用,通过引用路由路径和 "post" 方法来实现。

使用 Form 调用 action

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 调用 action

您可以使用 useSubmit 命令式地将表单数据提交给 action。

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 调用 action

Fetchers 允许您向 action(和 loader)提交数据,而不会导致导航(浏览器历史记录中不会添加新条目)。

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

有关更多信息,请参阅使用 Fetchers 指南。


下一步:导航

文档和示例 CC 4.0