Open6

Remix学習

おたきおたき

はじめに

Reactのフレームワークとして、Remixがシンプルでわかりやすいと聞いたので公式ドキュメントを中心に気になったことをまとめていこうと思う。
https://remix.run/

おたきおたき

Form vs. fetcher

https://remix.run/docs/en/main/discussion/form-vs-fetcher#form-vs-fetcher

下記のAPIを対象にいつ、なぜ使うのかを明確にすることが目標。

  • <Form>
  • useActionData
  • useFetcher
  • useNavigation

URLに

  • URL変更が必要である
    • ページ間の移動や遷移、またはレコード作成や削除などの特定アクション実行後。
  • URLの変更が必要でない
    • 現在のビューのコンテキストや主なコンテンツを大幅に変更しないアクションの場合。
    • 個々のフィールド更新や、新しい URL やページのリロードが不要なデータ操作が含まれる場合があり。ポップオーバーやコンボ ボックスなどのフェッチャーを使用したデータのロードにも当てはまる。
おたきおたき

Server vs. Client Code Execution

https://remix.run/docs/en/main/discussion/server-vs-client

Remixではビルドステップ時に、サーバー用とクライアント用のビルドを作成する。

  • サーバービルドの場合、すべてが1つのモジュールとなる
  • クライアントビルドの場合、複数のバンドルに分割される(ブラウザ読み込み最適化)

以下のルートモジュールの場合、action headers loaderがクライアントから削除。

routes/settings.tsx
import type {
  ActionFunctionArgs,
  HeadersFunction,
  LoaderFunctionArgs,
} from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

import { getUser, updateUser } from "../user";

// クライアントビルドから削除
export const headers: HeadersFunction = () => ({
  "Cache-Control": "max-age=300, s-maxage=3600",
});

// クライアントビルドから削除 
export async function loader({
  request,
}: LoaderFunctionArgs) {
  const user = await getUser(request);
  return json({
    displayName: user.displayName,
    email: user.email,
  });
}

export default function Component() {
  const user = useLoaderData<typeof loader>();
  return (
    <Form action="/account">
      <h1>Settings for {user.displayName}</h1>

      <input
        name="displayName"
        defaultValue={user.displayName}
      />
      <input name="email" defaultValue={user.email} />

      <button type="submit">Save</button>
    </Form>
  );
}

// クライアントビルドから削除
export async function action({
  request,
}: ActionFunctionArgs) {
  const formData = await request.formData();
  const user = await getUser(request);

  await updateUser(user.id, {
    email: formData.get("email"),
    displayName: formData.get("displayName"),
  });

  return json({ ok: true });
}

また、*.client.tsx および *.server.tsxのルールに従えば、クライアントまたはサーバーからコードを強制的に取り出すことが可能。これはどういうとき使うんだ?

おたきおたき

状態管理

https://remix.run/docs/en/main/discussion/state-management

Reactでの状態管理

通常のReactでは、状態管理 = キャッシュ管理を指す事が多い。これはサーバーが真の情報源であり、クライアントの状態は主にキャッシュとして機能するため。

Remixによる状態の簡素化

  • ローダー、アクション、フォーム機能は再検証の自動同期を備えており、BEとFEのギャップをシームレスに橋渡ししている。
  • キャッシュ、ネットワーク通信、データ再検証を管理する必要がないためコンポーネント内のサーバーの状態を直接使用可能。

1. ネットワーク関連の状態

Remixがすでに管理しているもの

  • useNavigation
    • navigation.state、navigation.formData、navigation.location などにアクセス可能
  • useFetcher
    • fetcher.state、fetcher.formData、fetcher.data などとやり取りが簡潔になる
  • useLoaderData
    • ルートのデータにアクセス可能
  • useActionData
    • 最新のアクションのデータにアクセス可能

2. Remixでのデータ保存

stateとして保存したいデータは、Remixの自然な場所にある

  • URL Search Params:URL 内のパラメータ
  • Cookies:ユーザーデバイス保存される小さなデータ
  • Server Sessions:サーバー管理のユーザーセッション
  • Server Caches:サーバー側でのデータキャッシュ
おたきおたき

永続的なUIの状態

状態には以下3つの方法が存在し、それぞれトレードオフがある。

  • React state: シンプルだが一時的な状態管理を提供
  • ローカル ストレージ: 永続性を提供するが、同期要件と UI のちらつきがある。
  • Cookie: 追加のコード量を犠牲にして、堅牢で永続的な状態管理を実現。