使用 TanStack Router 实现 SSR

在 Nitro 中使用 Vite 结合 TanStack Router 实现客户端路由。
src/main.tsx
import { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";

// Import the generated route tree
import { routeTree } from "./routeTree.gen.ts";

// Create a new router instance
const router = createRouter({ routeTree });

// Register the router instance for type safety
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

// Render the app
const rootElement = document.querySelector("#root")!;
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <StrictMode>
      <RouterProvider router={router} />
    </StrictMode>
  );
}

设置 TanStack Router 与 React、Vite 和 Nitro。该设置提供基于文件的路由,具有类型安全的导航和自动代码拆分。

概览

在 Vite 配置中添加 Nitro Vite 插件

创建包含应用入口的 HTML 模板

创建初始化路由的主入口文件

使用基于文件的路由定义路由

1. 配置 Vite

在 Vite 配置中添加 Nitro、React 和 TanStack Router 插件:

vite.config.mjs
import { defineConfig } from "vite";
import { nitro } from "nitro/vite";
import react from "@vitejs/plugin-react";
import { tanstackRouter } from "@tanstack/router-plugin/vite";

export default defineConfig({
  plugins: [tanstackRouter({ target: "react", autoCodeSplitting: true }), react(), nitro()],
});

tanstackRouter 插件根据你的 routes/ 目录结构生成路由树。启用 autoCodeSplitting 以自动将路由拆分成独立代码块。请将 TanStack Router 插件放在 React 插件之前。

2. 创建 HTML 模板

创建一个作为应用外壳的 HTML 文件:

index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Nitro + TanStack Router + React</title>
  </head>

  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

3. 创建应用入口

创建初始化 TanStack Router 的主入口文件:

src/main.tsx
import { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";

// 导入自动生成的路由树
import { routeTree } from "./routeTree.gen.ts";

// 创建新的路由实例
const router = createRouter({ routeTree });

// 注册路由实例以支持类型安全
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

// 渲染应用
const rootElement = document.querySelector("#root")!;
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <StrictMode>
      <RouterProvider router={router} />
    </StrictMode>
  );
}

routeTree.gen.ts 文件根据 routes/ 目录结构自动生成。Register 接口声明提供了关于路由路径和参数的完整类型推断。!rootElement.innerHTML 检查防止热模块替换时的重复渲染。

4. 创建根路由

根路由(__root.tsx)定义应用的布局:

src/routes/__root.tsx
import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";

const RootLayout = () => (
  <>
    <div className="p-2 flex gap-2">
      <Link to="/" className="[&.active]:font-bold">
        首页
      </Link>
    </div>
    <hr />
    <Outlet />
    <TanStackRouterDevtools />
  </>
);

export const Route = createRootRoute({ component: RootLayout });

使用 Link 实现类型安全的导航,并带有激活状态样式。Outlet 组件渲染子路由。包含 TanStackRouterDevtools 用于开发调试(生产环境会自动移除)。

5. 创建页面路由

页面路由使用 createFileRoute,可以包含加载器:

src/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
  loader: async () => {
    const r = await fetch("/api/hello");
    return r.json();
  },
  component: Index,
});

function Index() {
  const r = Route.useLoaderData();

  return (
    <div className="p-2">
      <h3>{JSON.stringify(r)}</h3>
    </div>
  );
}

使用 loader 函数在渲染前获取数据——数据通过 Route.useLoaderData() 可用。文件路径对应 URL 路径:routes/index.tsx 映射为 /routes/about.tsx 映射为 /aboutroutes/users/$id.tsx 映射为 /users/:id

更多学习资源