mcpField
R
react-web-advanced

react-web-advanced

github.com/trancong12102開発748 回インストール5 週間前に更新
リポジトリ

react-web-advanced について

react-web-advancedは、TanStack Router、TanStack Start、TanStack Virtualを使うReact Webアプリ向けの実装パターンをまとめたスキルです。Web開発者を対象に、ルーティング、サーバーサイドレンダリング、データ読み込み、大規模リストとReact Queryの連携を扱います。

主な機能

  1. 01TanStack RouterによるルーティングとURL状態管理
  2. 02TanStack Startのサーバー関数とSSR
  3. 03TanStack Virtualによる大規模リストの仮想化
  4. 04React Queryと連携するルートローダー
  5. 05コード分割とSuspenseのパターン

活用シーン

  1. 01型安全なナビゲーションと検索パラメーターの実装
  2. 02ルート読み込み時のデータ取得と事前取得
  3. 03大量の項目を含むリストの表示
  4. 04SSRと認証付きルートフローの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trancong12102/agentskills --skill react-web-advanced

インストール後、Claude Code で/react-web-advancedを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
better-auth-start.md
integration.md
router.md
ssr-auth.md
start.md
testing.md
virtual.md

詳細

React Web Advanced:TanStack Router、Start、Virtual

TanStack Router + Start + Virtual スタック上に構築された React アプリ向けの、Web 固有のパターンです。 このスキルは、コアとなるクロスプラットフォームのパターンを扱う react-advanced を拡張します。React Query、XState、Zustand、Zod、TanStack Form、TanStack Table の規約については、まずそちらのスキルをお読みください。

Web アーキテクチャ

Web スタックでは、共通のコアに次の 3 つのレイヤーを追加します。

レイヤーライブラリ役割
ルーティング + URL の状態TanStack Router型安全なナビゲーション、検索パラメーター、ルートローダー
フルスタック境界TanStack Startサーバー関数(createServerFn)、SSR、ストリーミング
大規模リストTanStack Virtual1000 件以上の項目の仮想化レンダリング
黄金律:唯一の信頼できる情報源としての queryOptions

クエリオプションを一度定義し、ローダー、コンポーネント、無効化処理など、あらゆる場所でインポートします。

// queries/posts.ts
export const postsQueryOptions = queryOptions({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  staleTime: 30_000,
});
Router と React Query の連携

Router はコンテキストとして QueryClient を受け取ります。これが唯一の連携ポイントです。

const router = createRouter({
  routeTree,
  context: { queryClient },
  defaultPreload: "intent",
  defaultPreloadStaleTime: 0, // Let React Query manage staleness
});

declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

defaultPreloadStaleTime: 0 は意図的な設定です。これがないと、Router はローダーの結果を独立してキャッシュするため、プリロード中に React Query の staleTime が無視されます。


ルートローダー + React Query のパターン

ブロッキング処理には ensureQueryData、ノンブロッキング処理には prefetchQuery
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ context: { queryClient }, params }) => {
    // Fire-and-forget secondary data
    queryClient.prefetchQuery(commentsQueryOptions(params.postId))
    // Block route render until critical data is ready
    await queryClient.ensureQueryData(postQueryOptions(params.postId))
  },
  component: PostDetail,
})

function PostDetail() {
  const { postId } = Route.useParams()
  // Data guaranteed in cache — instant, no loading state
  const { data: post } = useSuspenseQuery(postQueryOptions(postId))
  return <h1>{post.title}</h1>
}
ウォーターフォールリクエストを避ける

ルートローダーで Promise.all を使い、独立したデータをすべてプリフェッチします。

loader: async ({ context: { queryClient }, params }) => {
  await Promise.all([
    queryClient.ensureQueryData(userQueryOptions(params.id)),
    queryClient.ensureQueryData(permissionsQueryOptions(params.id)),
  ]);
  // Fire-and-forget for non-critical
  queryClient.prefetchQuery(activityQueryOptions(params.id));
};
  • ルートローダーで取得できるデータを useEffect で取得しないでください
  • 親ルートと子ルートのローダーは、デフォルトで並行して実行されます

パフォーマンスパターン

React Compiler(React 19 以降)

コンパイラーを有効にしている場合:

  • コンポーネントを手動で React.memo でラップしないでください
  • パフォーマンス向上を目的として、手動で useMemo / useCallback を使わないでください
  • 慣用的な React の書き方に従ってください。メモ化はコンパイラーが処理します
  • コードが Rules of React に従っていることを確認してください(レンダー中に変更しない)

手動での useMemo / useCallback は、エフェクトの依存関係を制御する場合にのみ引き続き役立ちます。

Suspense 境界の配置
  • ルートレベルの境界:ルート定義で pendingComponent / errorComponent を使用します
  • ルート内:ノンブロッキングデータを個別に <Suspense> でラップします
  • 依存関係のあるクエリは 1 つの <Suspense> の下にまとめ、同時に解決されるようにします
  • 独立したクエリには、それぞれ別の <Suspense> 境界を設定します
コード分割
  • .lazy() または .lazy.tsx ファイルを使ってルートを分割します。重要な設定(ローダー、パラメーター)はメインファイルに残し、コンポーネント/UI は遅延読み込みファイルに分割します
  • 重いオンデマンドコンポーネント(リッチエディター、グラフ)には React.lazy を使用します
  • マシン定義は別個の .ts ファイルであるため、自動的に分割されます

ファイル構成

src/
  routes/                  # TanStack Router file-based routes
    __root.tsx             # Root layout, router context type
    (auth)/                # Route group — no URL impact
    (app)/
      users/
        $userId.tsx
        $userId.lazy.tsx   # Component-only code split
        -components/       # "-" prefix excludes from route tree
  queries/                 # queryOptions definitions — one file per entity
  mutations/               # useMutation wrappers
  machines/                # XState machine definitions (pure TS, no React)
  stores/                  # Zustand stores
  serverFns/               # TanStack Start server functions
  components/
    ui/                    # Design system primitives
    shared/                # Cross-feature shared components
  lib/
    query-client.ts        # QueryClient singleton
    router.ts              # Router singleton
  test/
    setup.ts               # Vitest setup
    test-utils.tsx         # renderWithProviders
    mocks/handlers.ts      # MSW handlers

主な規約:

  • ルート固有のコンポーネントは、ルートツリーに含まれないように - プレフィックス付きのディレクトリに配置します
  • URL に影響を与えずに整理するには、パスレスルートグループ (name)/ を使用します
  • .lazy.tsx ファイルがエクスポートするのは、component/pendingComponent/errorComponent のみです
  • テストファイルはソースファイルの隣に配置します(.test.ts / .test.tsx)

よくある落とし穴

  1. createFileRoute のプロパティの順序が間違っている — TypeScript の型推論には、 validateSearch -> loaderDeps -> beforeLoad -> loader の順にする必要があります。 create-route-property-order ルールを含む @tanstack/eslint-plugin-router をインストールしてください。

  2. loaderDeps で検索パラメーター全体を返す — パラメーターが変更されるたびにキャッシュが無効になります。 ローダーが使用する依存関係のみを抽出してください。

  3. React Query のキャッシュを使わずに preload="intent" を使用する — ユーザーが 遷移しないと、プリロードされたデータは破棄されます。キャッシュを保持するには、React Query の ensureQueryData と組み合わせてください。

  4. ルーターを登録していない — declare module Register がないと、すべてが any になります。

  5. <Await> を <Suspense> で囲み忘れる — Suspense の祖先要素がないと、実行時エラーになります。

  6. defaultPreloadStaleTime を 0 に設定していない — Router のデフォルトの staleTime が プリロード時に React Query の staleTime を上書きするため、古いデータが返されます。

  7. notFoundComponent で useLoaderData を使う — 使用できません。Route.useParams() を使うか、 throw notFound({ data: ... }) を介してデータを渡してください。

  8. 認証フローを検証する前にすべてのページを作成する — 機能ページの作成に取りかかる前に、 認証フロー(ログイン → セッション Cookie → 保護されたルートガード → リダイレクト)をまず実装し、 エンドツーエンドで検証してください。認証統合のバグは互いに隠れ合います(7 層以上深くに潜むこともあります)。 references/ssr-auth.md を参照してください。

  9. defaultPreload: "intent" によってホバー時に認証チェックが実行される — intent プリロードでは、 リンクにホバーするたびに beforeLoad が実行されます。beforeLoad が認証検証を行う場合、ホバーのたびに セッションチェックが実行されます。認証のデバッグ中は intent プリロードを無効にするか、認証チェックを キャッシュ対応にしてください(フェッチする前に queryClient.getQueryData(sessionKey) を確認します)。

  10. invalidateQueries() の無差別な呼び出しが認証フックに連鎖する — キーフィルターを指定せずに queryClient.invalidateQueries() を呼び出すと、セッションクエリを含む すべてが無効になります。認証のリアクティブフックが再フェッチし、コンポーネントが再レンダリングされ、 beforeLoad が再実行されます。常に特定のエンティティクエリキーに絞って無効化してください。 クエリキーの名前空間パターンについては、references/integration.md を参照してください。

  11. 認証用 nanostores が API の変更のたびに再レンダリングを引き起こす — Better Auth などの ライブラリは内部で nanostores を使用します。変更が成功するたびにシグナルが切り替わり、 すべての useSession()/useActiveOrganization() の購読者が同期的に再レンダリングされます。 TanStack Router と組み合わせると、無限の再レンダリングループが発生します。認証フックを React Query の ラッパーに置き換えてください。references/better-auth-start.md を参照してください。

  12. クライアント側のナビゲーションのたびに beforeLoad が再実行される — beforeLoad 内の セッションチェックが React Query のキャッシュなしでサーバー関数を呼び出す場合、リンクをクリックするたびに サーバーへの往復が発生します。キャッシュからデータを返せるよう、staleTime を指定して ensureQueryData を使用してください。references/ssr-auth.md を参照してください。


リファレンスファイル

特定のライブラリを使用する場合は、該当するリファレンスファイルを読んでください。

ファイル読むタイミング
references/router.mdルーティング、検索パラメーター、ローダー、コード分割、ナビゲーション
references/start.mdサーバー関数、SSR、ミドルウェア、デプロイ
references/virtual.md仮想化、動的な高さ、無限スクロール、グリッド
references/integration.mdRouter と Query の連携、認証ガード、クエリキーの名前空間、組織データ
references/ssr-auth.mdSSR Cookie 認証、Vite プロキシ、CORS、ルートガード、FOUC、CF Workers
references/better-auth-start.mdBetter Auth + TanStack Start:シグナル、RQ ラッパー、組織の状態
references/testing.mdRouter のルートのテスト、renderWithProviders

コメント