アクション

データの変更は、ルートアクションを通して行われます。アクションが完了すると、ページ上のすべてのローダーデータが再検証され、UIをデータと同期した状態に保ちます。コードを記述する必要はありません。

actionで定義されたルートアクションはサーバーでのみ呼び出され、clientActionで定義されたアクションはブラウザで実行されます。

クライアントアクション

クライアントアクションはブラウザでのみ実行され、サーバーアクションの両方が定義されている場合、クライアントアクションが優先されます。

app/project.tsx
// 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 = await 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>
  );
}

サーバーアクション

サーバーアクションはサーバーでのみ実行され、クライアントバンドルから削除されます。

app/project.tsx
// 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 = await 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" メソッドを参照して呼び出されます。

<Form> を使用したアクションの呼び出し

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 を使用したアクションの呼び出し

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

詳細については、フェッチャの使用ガイドを参照してください。


次:ナビゲーション