ルーターこのページを編集.md

型付きルーター

@lazarv/react-serverには完全に型付けされたルーティングソリューションが含まれています。すべてのルート、リンク、パラメータ、検索パラメータをコンパイル時に型チェックでき、ルートパス、パラメータ、検索値のIDEオートコンプリートが利用できます。手動で実行するコード生成ステップや外部ツールは不要です。

ルートディスクリプタはどこでも使えます — サーバーコンポーネント、クライアントコンポーネント、共有モジュール。同じcreateRoute呼び出しから、型付きLinkコンポーネント、型付きフック(useParamsuseSearchParams)、型付きプログラムナビゲーション、そして任意のスキーマライブラリ(Zod、ArkType、Valibot、またはValidateSchemaインターフェースを満たすもの)や軽量パース関数によるオプションのランタイムバリデーションが得られます。

ファイルシステムベースのルーティングについては、これらのプリミティブを自動的に構築するファイルシステムベースのルーターを参照してください。低レベルのRouteコンポーネントAPIについては、以下のRouteコンポーネントを参照してください。

createRouteを使用して、完全な型安全性を持つルートディスクリプタを定義します。ルートディスクリプタはルートのパス、バリデーションルール、型付きヘルパーを保持し、サーバーコンポーネントとクライアントコンポーネントの両方からインポートできます。

routes.ts
import { createRoute } from "@lazarv/react-server/router"; // 静的ルート — パラメータなし export const home = createRoute("/", { exact: true }); // 動的ルート — パターンからパラメータを抽出 export const user = createRoute("/user/[id]", { exact: true }); // キャッチオールルート — パラメータはstring[] export const docs = createRoute("/docs/[...slug]"); // フォールバックルート — 他にマッチしない場合にマッチ export const notFound = createRoute("*"); // スコープ付きフォールバック — /user/配下で他のルートが処理しないものにマッチ export const userNotFound = createRoute("/user/*");

パスパターンがパラメータの型を自動的に決定します:

パターン抽出される型
/user/[id]{ id: string }
/blog/[slug]/[commentId]{ slug: string; commentId: string }
/files/[...path]{ path: string[] }
*{}

スコープ付きフォールバックは、他のルートが処理しない場合にプレフィックス配下のURLにのみマッチします。これはコンテキスト固有の404ページを表示するのに便利です — 例えば、ユーザーが見つからないページで「ユーザーを検索」UIを表示し、グローバルな*フォールバックでは汎用メッセージを表示できます。

サーバーサイドでは、ルートディスクリプタをReact要素にバインドし、ルーターに収集します。ルーターはマッチしたルートをレンダリングする<Routes />コンポーネントを提供します。ルーター定義をレイアウトから分離すると、各ファイルが単一の関心事に集中できます。

router.tsx
import { createRoute, createRouter } from "@lazarv/react-server/router"; import * as routes from "./routes"; import Home from "./Home"; import UserPage from "./UserPage"; import NotFound from "./NotFound"; const router = createRouter({ home: createRoute(routes.home, <Home />), user: createRoute(routes.user, <UserPage />), notFound: createRoute(routes.notFound, <NotFound />), }); export default router;
App.tsx
import router from "./router"; export default function App() { return ( <div> <nav> <router.home.Link>Home</router.home.Link> <router.user.Link params={{ id: 42 }}>User 42</router.user.Link> </nav> <router.Routes /> </div> ); }

createRoute(descriptor, element)オーバーロードは、既存のルートディスクリプタを受け取りReact要素にバインドし、.Routeコンポーネントを持つ完全なTypedRouteを生成します。createRouter関数はこれらをルーターオブジェクトに収集し、各ルートは名前でアクセスできます。

ルートディスクリプタにサーバーコンポーネントは不要です。クライアント上でのみ存在するルートを作成できます — タブ、モーダル状態、フィルター、またはサーバーラウンドトリップなしでURLに基づいてUIを変更する場合に便利です。

パスとオプションだけでcreateRouteを呼び出すと(要素なし)、.Link.href().useParams().useSearchParams()を持つルートディスクリプタが得られます。これらのディスクリプタを"use client"コンポーネントで使用すると、ルーティングは完全にクライアント上で行われます。

routes.ts
import { createRoute } from "@lazarv/react-server/router"; import { z } from "zod"; export const settings = createRoute("/settings/[tab]", { exact: true, validate: { params: z.object({ tab: z.enum(["profile", "security", "billing"]), }), }, });
SettingsPage.tsx
"use client"; import { settings } from "./routes"; export default function SettingsPage() { const params = settings.useParams(); const tab = params?.tab ?? "profile"; return ( <div> <nav> <settings.Link params={{ tab: "profile" }}>Profile</settings.Link> <settings.Link params={{ tab: "security" }}>Security</settings.Link> <settings.Link params={{ tab: "billing" }}>Billing</settings.Link> </nav> {tab === "profile" && <ProfileForm />} {tab === "security" && <SecuritySettings />} {tab === "billing" && <BillingInfo />} </div> ); }

ファイルシステムベースのルーターでは、先頭に"use client"を持つページは自動的にクライアント専用ルートになります。ディレクティブとデフォルトエクスポートを持つページファイルを作成するだけです:

pages/counter.tsx
"use client"; import { useState } from "react"; export default function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>Count: {count}</button>; }
pages/clock.tsx
"use client"; import { useState, useEffect } from "react"; export default function Clock() { const [time, setTime] = useState(new Date()); useEffect(() => { const id = setInterval(() => setTime(new Date()), 1000); return () => clearInterval(id); }, []); return <p>Current time: {time.toLocaleTimeString()}</p>; }

これらのページはクライアントルートストアに自動的に登録されます。これらの間のナビゲーションは完全にクライアント上で行われ — サーバーラウンドトリップなしで、ReactのActivityコンポーネントによるインスタントな表示/非表示トランジションでコンポーネントの状態が保持されます。

ルートがクライアントコンポーネントとして登録されている場合 — ファイルシステムルーター、<Route>コンポーネント、createRouterのいずれを通じても — ランタイムはクライアントサイドのルートストアで追跡します。ターゲットURLのすべてのルートがクライアント専用の場合、ナビゲーションは完全にクライアント上で行われ — サーバーリクエストは不要です。これにより、クライアント専用ルートはタブ、カウンター、時計、またはナビゲーションを超えて存続すべきステートフルUIなどの高速でインタラクティブなUIパターンに最適です。

クライアント専用ルートとサーバールートを自由に混在させることができます。プレーンな.tsファイルで共有ルートディスクリプタを定義し、両方の環境でインポートします:

routes.ts
import { createRoute } from "@lazarv/react-server/router"; // サーバーとクライアントの両方で動作 — ディスクリプタのみ(要素なし) export const home = createRoute("/"); export const user = createRoute("/user/[id]");

サーバーコンポーネントからインポートすると、useParams()はHTTPリクエストコンテキストから読み取ります。クライアントコンポーネントからインポートすると、ブラウザのロケーションから読み取ります。ランタイムはViteエイリアスを介して正しい実装を解決するため、どこでも同じコードを書くことができます。

すべてのルートディスクリプタには、コンパイル時に正しいパラメータと検索型を強制する.Linkコンポーネントがあります。動的セグメントのないルートはparamsを受け付けません。動的セグメントを持つルートはparamsが必須です。

// パラメータなし — paramsを渡すとTypeScriptエラー <home.Link>Home</home.Link> // 必須パラメータ — paramsを省略するとTypeScriptエラー <user.Link params={{ id: 42 }}>User 42</user.Link> // 検索パラメータ付き <post.Link params={{ slug: "hello" }} search={{ tab: "comments" }}> Post </post.Link> // すべての標準Linkプロップ(prefetch、rollbackなど)がサポートされます <user.Link params={{ id: 1 }} prefetch>User 1</user.Link>

フォールバックルート(*)にはアドレス指定可能なパスがないため、.Linkコンポーネントはありません。

ルートディスクリプタは、型付きでバリデーション済みのパラメータと検索パラメータを返すフックを提供します。これらのフックはサーバーコンポーネント(RSC)とクライアントコンポーネントの両方で動作します。

UserPage.tsx
import { user } from "./routes"; export default function UserPage() { // ルートがマッチしない場合は型付きパラメータまたはnullを返す const params = user.useParams(); // params: { id: string } | null if (!params) return <p>No match</p>; return <h2>User {params.id}</h2>; }
ProductList.tsx
"use client"; import { products } from "./routes"; export default function ProductList() { // デフォルト付きのバリデーション済み検索パラメータを返す const { sort, page } = products.useSearchParams(); // sort: "name" | "price" | "rating", page: number return <div>Sorted by {sort}, page {page}</div>; }

サーバーでは、useParams()はHTTPリクエストコンテキストからパラメータを読み取ります。クライアントでは、ブラウザのロケーションから読み取ります。同じルートディスクリプタが両方の環境で動作します — ランタイムがViteエイリアスを介して正しい実装を解決します。

各ルートディスクリプタには、型付きパラメータからURLパス名を構築するhref()メソッドがあります:

user.href({ id: 42 }); // → "/user/42" post.href({ slug: "hello" }); // → "/post/hello" home.href(); // → "/"

これはJSXの外でURLを生成するのに便利です — サーバー関数、APIハンドラー、リダイレクト、メタデータなどで。

@lazarv/react-server/navigationuseNavigateフックは、型安全なプログラムナビゲーションのためにルートディスクリプタを受け付けます:

"use client"; import { useNavigate } from "@lazarv/react-server/navigation"; import { user, products } from "./routes"; export default function SearchButton() { const navigate = useNavigate(); return ( <button onClick={() => navigate(user, { params: { id: 42 } })}> Go to User 42 </button> ); }

型付きルートにナビゲーションする場合、検索パラメータは現在のURL検索パラメータにマージされます — 変更したいパラメータのみを指定します。

ルートパラメータと検索パラメータは、ValidateSchemaインターフェースを満たす任意のスキーマライブラリを使用してランタイムでバリデーションできます。ランタイムは3つのバリデーション戦略を順に試行します:

  1. .safeParse(data) — Zod、Valibot、および互換ライブラリ
  2. .assert(data) — ArkType(失敗時にスロー、成功時にTを返す)
  3. .parse(data) — 汎用フォールバック(失敗時にスロー)
// これらの形状のいずれかがValidateSchema<T>を満たします: // Zod / Valibotスタイル interface SafeParseSchema<T> { parse(data: unknown): T; safeParse(data: unknown): { success: true; data: T } | { success: false; error: unknown }; } // ArkTypeスタイル interface AssertSchema<T> { assert(data: unknown): T; } // 汎用パーススタイル interface ParseSchema<T> { parse(data: unknown): T; }

TypeScriptはスキーマの出力型からパラメータと検索型を推論します。例えば、z.object({ id: z.coerce.number() })を渡すと、TypeScriptは.parse(){ id: number }を返すことを認識し、その型をuseParams().Link.href()に流します。これは構造的型付けです — 特定のライブラリへの依存はありません。

Zodの場合:

routes.ts
import { createRoute } from "@lazarv/react-server/router"; import { z } from "zod"; export const user = createRoute("/user/[id]", { exact: true, validate: { params: z.object({ id: z.coerce.number().int().positive(), }), }, }); export const products = createRoute("/products", { exact: true, validate: { search: z.object({ sort: z.enum(["name", "price", "rating"]).catch("name"), page: z.coerce.number().int().positive().catch(1), }), }, });

ArkTypeの場合:

routes.ts
import { createRoute } from "@lazarv/react-server/router"; import { type } from "arktype"; export const user = createRoute("/user/[id]", { exact: true, validate: { params: type({ id: "string.numeric.parse" }), }, }); export const products = createRoute("/products", { exact: true, validate: { search: type({ "sort?": "'name' | 'price' | 'rating'", "page?": "string.numeric.parse", }), }, });

この設定では:

バリデーション済みの型はフックと.Linkコンポーネントに流れます — IDEは生の文字列ではなくバリデーション済みの型を表示します。

完全なスキーマライブラリが不要な場合は、parseを使用して軽量な型変換とバリデーションを行います。各キーは生の文字列を目的の型に変換する関数にマップします。

routes.ts
import { createRoute } from "@lazarv/react-server/router"; export const post = createRoute("/post/[slug]", { exact: true, parse: { params: { slug: String }, search: { tab: (v) => ["content", "comments", "related"].includes(v) ? v : "content", q: String, }, }, });

NumberBooleanStringDateなどの組み込みコンストラクタはパース関数として直接使用できます。カスタム関数で制約を強制できます — 上の例では、tabは許可リストに対してバリデーションし、不明な値には"content"にフォールバックします。

パース関数は次の場合に適しています:

複雑なスキーマ、ネストされたオブジェクト、詳細なエラーメッセージが必要な場合は、スキーマライブラリとvalidateを使用してください。

型付きLinkコンポーネントとuseNavigateの両方が検索パラメータの関数型アップデーターをサポートしています。静的オブジェクトの代わりに、現在の検索パラメータを受け取り新しい値を返す関数を渡します:

// Linkで関数型アップデーター <products.Link search={(prev) => ({ ...prev, page: prev.page + 1 })}> Next Page </products.Link> // useNavigateで関数型アップデーター navigate(products, { search: (prev) => ({ ...prev, sort: "price", page: 1 }), });

関数型アップデーターはクリック時に現在のパラメータを読み取るため、複数の更新が連続して発生する場合のステールクロージャバグを回避します。また、完全な現在の状態を事前に知る必要なく、一つのパラメータを変更しながら残りを保持するデルタ更新が容易になります。

SearchParamsコンポーネントは、URLとアプリケーション間の双方向変換レイヤーを提供します。コンパクトなURL形式を構造化パラメータにデコードしたり、コンポーネントに渡す前にトラッキングパラメータを除去するために使用します。

各ルートディスクリプタには、そのルートがマッチした場合にのみアクティブになるルートスコープのSearchParamsコンポーネントがあります:

StripTrackingParams.tsx
"use client"; import { products } from "./routes"; // URLには?price=min-maxを保存するが、アプリには?min_price & ?max_priceを公開 function decode(sp) { const range = sp.get("price"); if (!range) return sp; const [min, max] = range.split("-"); const result = new URLSearchParams(sp); result.delete("price"); result.set("min_price", min); result.set("max_price", max); return result; } function encode(sp) { const min = sp.get("min_price"); const max = sp.get("max_price"); if (min == null && max == null) return sp; const result = new URLSearchParams(sp); result.delete("min_price"); result.delete("max_price"); result.set("price", `${min ?? 0}-${max ?? 10000}`); return result; } export default function ProductPriceRange({ children }) { return ( <products.SearchParams decode={decode} encode={encode}> {children} </products.SearchParams> ); }

ネストがサポートされています — decodeは外→内にチェーンされ、encodeは内→外にチェーンされます。ルーターはcreateRouterを通じてすべてのルートに適用されるグローバルSearchParamsコンポーネントも公開します。

スキーマバリデーション、軽量パース、createRouterを使用した完全な型付きルーターのセットアップ例:

routes.ts
import { createRoute } from "@lazarv/react-server/router"; import { z } from "zod"; export const home = createRoute("/", { exact: true }); export const about = createRoute("/about", { exact: true }); export const user = createRoute("/user/[id]", { exact: true, validate: { params: z.object({ id: z.coerce.number().int().positive() }), }, }); export const post = createRoute("/post/[slug]", { exact: true, parse: { params: { slug: String }, search: { tab: (v) => ["content", "comments", "related"].includes(v) ? v : "content", q: String, }, }, }); export const notFound = createRoute("*");
router.tsx
import { createRoute, createRouter } from "@lazarv/react-server/router"; import * as routes from "./routes"; import Home from "./Home"; import About from "./About"; import UserPage from "./UserPage"; import PostPage from "./PostPage"; import NotFound from "./NotFound"; const router = createRouter({ home: createRoute(routes.home, <Home />), about: createRoute(routes.about, <About />), user: createRoute(routes.user, <UserPage />), post: createRoute(routes.post, <PostPage />), notFound: createRoute(routes.notFound, <NotFound />), }); export default router;
App.tsx
import router from "./router"; export default function App() { return ( <div> <nav> <router.home.Link>Home</router.home.Link> <router.about.Link>About</router.about.Link> <router.user.Link params={{ id: 42 }}>User 42</router.user.Link> <router.post.Link params={{ slug: "hello-world" }} search={{ tab: "comments" }} > Hello World </router.post.Link> </nav> <router.Routes /> </div> ); }

注意: 完全な動作例については、リポジトリ内のtyped-routertyped-file-routerのサンプルをチェックしてください。

すべての型付きルーターエクスポートは@lazarv/react-server/routerから利用できます。

ルートディスクリプタまたは完全な型付きルートを作成します。返される型は引数によって異なります:

ルートディスクリプタ(要素なし) — RouteDescriptorを返します。.Link.href().useParams().useSearchParams().SearchParamsを持ちますが、.Routeはありません。サーバーとクライアントの両方のコンポーネントで安全にインポートできます。

createRoute(path, options?) // → RouteDescriptor createRoute("*", options?) // → RouteDescriptor(フォールバック) createRoute("/prefix/*", options?) // → RouteDescriptor(スコープ付きフォールバック)

型付きルート(要素あり) — RouteDescriptorを拡張し.Routeコンポーネントを追加したTypedRouteを返します。サーバーエントリーポイントでReact要素をルートにバインドするために使用します。

createRoute(path, element, options?) // → TypedRoute createRoute("*", element, options?) // → TypedRoute(フォールバック) createRoute("/prefix/*", element, options?) // → TypedRoute(スコープ付きフォールバック) createRoute(element, options?) // → TypedRoute(グローバルフォールバック)

ディスクリプタから — 既存のRouteDescriptorを受け取り要素にバインドし、TypedRouteを生成します。これは推奨パターンです:共有ファイルでディスクリプタを定義し、サーバーエントリーポイントで要素をバインドします。

createRoute(descriptor, element) // → TypedRoute

オプション:

オプション説明
exactbooleanプレフィックスマッチではなく完全パスマッチ。デフォルト:false
validate{ params?, search? }ランタイムバリデーション用のスキーマオブジェクト。ValidateSchema<T>インターフェースを満たす任意のライブラリ(Zod、ArkType、Valibotなど)が使用可能 — TypeScriptがスキーマの出力型からパラメータ/検索型を推論
parse{ params?, search? }軽量パーサー関数マップ。各キーが生の文字列を目的の型にマップ
loadingReactNode | ComponentTypeルートのロード中に表示されるSuspenseフォールバック
matchersRecord<string, (value: string) => boolean>[param=matcher]構文のカスタムマッチャー
render(params) => ReactNodeパラメータとchildrenを受け取るレイアウト関数
childrenReactNodeルート内にレンダリングされるネストコンテンツ

validateparseは相互排他的な戦略です。互換ライブラリによるスキーマベースのバリデーションにはvalidateを、軽量な関数ベースの変換にはparseを使用してください。

createRoute(path, options?)で返されるオブジェクト — 要素がバインドされていないルート。クライアントコンポーネントや共有ルート定義ファイルで使用する形状です。

プロパティ / メソッド説明
pathstring | undefinedルートパスパターン
exactboolean完全一致が必要かどうか
fallbackbooleanフォールバックルートかどうか
validateRouteValidate | nullバリデーションスキーマ(提供された場合)
parseRouteParse | nullパース関数(提供された場合)
LinkReact.FC<...>型付きLinkコンポーネント。パスに動的セグメントがある場合はparamsが必須。searchをオブジェクトまたは関数型アップデーターとして受け付ける。フォールバックルートでは利用不可
href(params?)(params?) => string型付きパラメータからURLパス名を構築。フォールバックルートでは利用不可
useParams()() => TParams | null型付きパラメータを返すフック。ルートがマッチしないかバリデーションが失敗した場合はnull。サーバーとクライアントの両方のコンポーネントで動作
useSearchParams()() => TSearch型付き検索パラメータを返すフック。設定されている場合はバリデーションまたはパースを適用
SearchParamsReact.FC<SearchParamsProps>ルートスコープの検索パラメータ変換境界。このルートがマッチした場合にのみアクティブ

RouteDescriptor.Routeコンポーネントで拡張。要素が提供された場合にcreateRouteから返されます。

プロパティ説明
...すべてのRouteDescriptorプロパティ
RouteReact.FC<...>バインドされた要素をレンダリングするルートコンポーネント。オプションのオーバーライドを受け付ける:elementloadingrenderchildrenexactfallback

型付きルートをルーターオブジェクトに収集します。すべてのルートを名前で展開し、RoutesSearchParamsコンポーネントを追加したTypedRouterを返します。

const router = createRouter({ home: createRoute(routes.home, <Home />), user: createRoute(routes.user, <UserPage />), notFound: createRoute(routes.notFound, <NotFound />), });

TypedRouterプロパティ:

プロパティ説明
RoutesReact.FCすべてのルートを宣言順にレンダリング。ルートコンテンツを表示したい場所に配置
SearchParamsReact.FC<SearchParamsProps>グローバル検索パラメータ変換境界 — すべてのルートに適用
[routeName]TypedRoute各ルートはcreateRouterに渡したキーでアクセス可能。router.user.Linkrouter.user.useParams()など

双方向の検索パラメータ変換境界。スタンドアロンコンポーネント、各ルートディスクリプタ、ルーターオブジェクトとして利用可能です。

import { SearchParams } from "@lazarv/react-server/router"; // スタンドアロン — 内部のすべてのルートに適用 <SearchParams decode={decode} encode={encode}> {children} </SearchParams> // ルートスコープ — このルートがマッチした場合のみ適用 <products.SearchParams decode={decode} encode={encode}> {children} </products.SearchParams> // ルーターレベル — ルーター内のすべてのルートに適用 <router.SearchParams decode={decode} encode={encode}> {children} </router.SearchParams>

プロップ:

プロップ説明
decode(sp: URLSearchParams) => URLSearchParamsフックとバリデーションが読み取る前にURLパラメータを変換
encode(sp: URLSearchParams, current: URLSearchParams) => URLSearchParamsURLに書き込まれる前にマージされたパラメータを変換
childrenReactNode

低レベルのRouteコンポーネントはJSXによる基本的なパスマッチングを提供します。シンプルなユースケースや、型付きディスクリプタなしでルートレンダリングを直接制御したい場合に便利です。

import { Route } from '@lazarv/react-server/router'; export default function App() { return ( <Route path="/about"> <About /> </Route> <Route path="/readme" element={<Readme />} /> ); }

ルートを定義すると、定義したパスで始まるすべてのパスにマッチします。完全一致にするにはexactプロップを使用します:

<Route path="/about" exact> <About /> </Route>

ルートのネスト、renderプロップによるレイアウトの定義、ルートパラメータの使用ができます:

import { Route } from '@lazarv/react-server/router'; function Layout({ children }) { return ( <div> <h1>Layout</h1> {children} </div> ); } function User({ id }) { return <h2>User {id}</h2>; } export default function App() { return ( <Route path="/" render={Layout}> <Route path="/" exact element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/users/[id]" render={User} /> <Route path="/files/[...path]" render={File} /> <Route fallback element={<NotFound />} /> </Route> ); }

ルートパラメータはcreateRouteと同じブラケット構文を使用します:[id]は単一パラメータ、[...path]はキャッチオールパラメータ。カスタムマッチャーも定義できます:

const matchers = { number: (value) => /^\d+$/.test(value), }; <Route path="/files/[id=number]" render={File} matchers={matchers} />

フォールバックルートは他のルートがマッチしない場合にマッチします。path="*"またはfallbackプロップを使用します:

<Route path="/about" element={<About />} /> <Route fallback element={<NotFound />} />

より複雑なアプリケーションには、代わりにcreateRoutecreateRouterを使用してください — 型安全性、バリデーション、より良い開発者体験を提供します。Routeコンポーネントはクイックプロトタイプやシンプルなアプリに最適です。

コンポーネント内でredirect関数を使用することで、他の場所にリダイレクトできます。より正確には、サーバーサイドレンダリング中の任意の場所でredirectを使用できますが、RedirectErrorがスローされます。ランタイムはこのエラーをキャッチして、クライアントにリダイレクト応答を送信します。

import { redirect } from "@lazarv/react-server"; export default function App() { return redirect("/user"); }

kindパラメータを指定して、クライアントでのリダイレクトの動作を制御することもできます:

import { redirect } from "@lazarv/react-server"; export default function ProtectedPage() { // pushStateでリダイレクト(ユーザーが戻れるように) redirect("/login", 302, "push"); }

利用可能なリダイレクト種類:"navigate"(デフォルト、replaceState)、"push"(pushState)、"location"(完全なブラウザナビゲーション)、"error"(カスタム処理のためにクライアントでスロー)。詳細はHTTPリダイレクトのドキュメントを参照してください。

現在のリクエストのURL内のパス名を変更するためにrewrite関数を使用できます。これはクライアントをリダイレクトせずにURLを変更したい場合に便利です。ミドルウェアで使用するのに最適です。

import { rewrite } from "@lazarv/react-server"; export default function App() { return rewrite("/user"); }

サーバー関数では、reload関数を使って現在のページやアウトレットをリロードできます。これはミューテーション後にアプリの要素をリフレッシュするためにページやアウトレットをリロードしたい場合に便利です。

"use server"; import { reload } from "@lazarv/react-server"; export async function addTodo(todo) { await addTodo(todo); reload(); }

reload関数にURLとアウトレット名を渡して、別のルートとアウトレットをレンダリングすることもできます。この方法を使えば、サーバー関数を使ってデータを変更する場合でも、アプリ全体の不要な再レンダリングを回避してパフォーマンスを最適化できます。

"use server"; import { reload } from "@lazarv/react-server"; export async function addTodo(todo) { await addTodo(todo); reload("/todos", "todo-list"); }

ミドルウェアはルートハンドラの前に実行される関数です。認証、ロギング、解析など、さまざまなことに使用できます。

エントリモジュールからinit$という名前のasync関数をエクスポートしてください。この関数はミドルウェアランナーとなるリクエストハンドラを初期化します。init$関数はasync関数を返す必要があります。この関数がミドルウェアランナーとなります。

// index.jsx export async function init$() { return async (context) { // do something }; }

@lazarv/react-serverモジュールから利用可能なすべての関数をミドルウェアで使用できます。リクエストをリダイレクトしたり書き換えたり、クッキーを管理したり、レスポンスにヘッダーを追加したりできます。React Server Componentで使える機能は、ミドルウェアでもすべて利用可能です。