Skip to content
开发工具与调试

开发工具与调试

TanStack Router 提供了专用的 Devtools 面板和多种调试手段,帮助可视化路由状态、追踪导航流程、排查路由问题。


安装 Devtools

npm install -D @tanstack/react-router-devtools
# 或
npm install -D @tanstack/router-devtools

基础使用

// src/App.tsx
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import { RouterProvider } from '@tanstack/react-router'
import { router } from './router'

function App() {
  return (
    <>
      <RouterProvider router={router} />
      {/* 仅在开发环境显示 */}
      <TanStackRouterDevtools router={router} />
    </>
  )
}

💡 最佳实践:Devtools 默认只在 development 模式下显示。生产环境可以用条件包裹:

{import.meta.env.DEV && <TanStackRouterDevtools router={router} />}

Devtools 面板位置

// 调整面板位置(默认在右下角)
<TanStackRouterDevtools
  router={router}
  position="bottom-left"  // 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'
/>

// 自定义面板样式
<TanStackRouterDevtools
  router={router}
  panelStyle={{ height: '600px' }}
/>

Devtools 功能

路由树可视化

Devtools 展示完整的路由树结构,包括:

  • 每个路由的路径、状态(active / inactive)
  • Loader 状态(pending / loaded / error)
  • 路径无关布局的层级关系
  • 当前匹配的路由高亮

路由匹配信息

点击任意路由可查看详细信息:

  • 当前参数:path params 和 search params 的实际值
  • Loader 数据:缓存的 loader 返回值
  • Context:路由上下文内容
  • 匹配状态:为什么匹配成功/失败

导航历史

显示最近的导航记录:

  • 从哪个路由 → 到哪个路由
  • 导航触发原因(用户点击 / 代码调用 / 浏览器前进后退)
  • 每次导航的耗时

缓存状态

查看 SWR 缓存信息:

  • 哪些路由的 loader 数据在缓存中
  • 缓存的 staleTime 和剩余时间
  • 手动清除缓存

生产环境使用 Devtools

TanStack Router Devtools 在默认情况下生产环境不渲染任何 UI,但你可以强制显示(例如用于 staging 调试):

<TanStackRouterDevtools
  router={router}
  initialIsOpen={false} // 初始不展开面板
/>

🚨 陷阱:不要将 devtools 面板在生产环境对普通用户开放——它会暴露路由结构、loader 数据等内部信息。如确需在 staging 使用,确保只有内部人员可访问。


调试常见路由问题

1. 路由不匹配

如果页面显示 404 而非预期内容:

  1. 打开 Devtools → 查看路由树是否包含该路由
  2. 检查 routeTree.gen.ts 是否正确生成(删除后重新 npm run dev
  3. 确认文件命名是否符合约定($param_layout 等)
常见错误:
routes/user/$id.tsx       ❌ 应为 routes/users/$userId.tsx
routes/posts/new.tsx      ✅ 但如果 $postId 也在 posts/ 下会冲突

2. 搜索参数类型错误

// 调试 validateSearch
export const Route = createFileRoute('/test')({
  validateSearch: (search) => {
    console.log('原始 search 参数:', search) // 👈 调试入口
    return { page: Number(search.page) || 1 }
  },
})

3. Loader 不执行或执行异常

export const Route = createFileRoute('/posts/')({
  loader: async ({ params, deps, cause, preload }) => {
    console.log('Loader 触发:', { params, deps, cause, preload })
    // cause: 'enter' (首次进入) | 'stay' (staleTime 内重新进入)
    // preload: true/false
    return fetchPosts(deps.page)
  },
})

4. 使用 Devtools 的 “Test” 功能

Devtools 面板提供内置的路由测试功能:

  • 手动输入路径查看哪个路由会匹配
  • 模拟搜索参数验证结果
  • 测试 beforeLoad 守卫逻辑

编程式调试

获取当前路由状态

import { useRouterState } from '@tanstack/react-router'

function DebugPanel() {
  const state = useRouterState()

  return (
    <details>
      <summary>Router State</summary>
      <pre>{JSON.stringify({
        location: state.location,
        matches: state.matches.map((m) => m.routeId),
        status: state.status,
      }, null, 2)}</pre>
    </details>
  )
}

监听路由事件

import { useRouter } from '@tanstack/react-router'

function App() {
  const router = useRouter()

  useEffect(() => {
    const unsubscribe = router.subscribe('onBeforeNavigate', ({ toLocation }) => {
      console.log('即将导航到:', toLocation.href)
    })

    return unsubscribe
  }, [router])
}

💡 最佳实践:路由事件监听适合做页面加载进度条(NProgress 风格),在 onBeforeNavigate 开始、onResolved 结束。

类型调试

如果类型推断不符合预期:

// 检查 Route 的类型
import type { Route } from '@tanstack/react-router'

// 利用 TypeScript 的类型提示
const _typeCheck: typeof Route.types.loaderData = {} as any
// 悬停在 _typeCheck 上即可看到 loader 的完整返回类型

常见调试流程

问题 首要检查 工具
页面 404 路由树是否包含该路由 Devtools → Route Tree
Loader 数据不对 loader 参数和返回值 console.log + Devtools → Loader Data
导航不跳转 beforeLoad 是否抛出了 redirect Devtools → Navigation History
搜索参数丢失 是否用了函数式更新器 Devtools → Search Params
类型报错 是否执行了 declare module Register 检查 router.tsx 类型注册
路由树未更新 routeTree.gen.ts 是否过期 删除后重启 dev server

Vite 插件调试

// vite.config.ts
import { tanstackRouter } from '@tanstack/router-plugin/vite'

export default defineConfig({
  plugins: [
    tanstackRouter({
      // 输出路由生成日志
      logs: true,
      // 自定义路由树输出路径
      routesDirectory: './src/routes',
      generatedRouteTree: './src/routeTree.gen.ts',
    }),
    react(),
  ],
})

💡 最佳实践:如果路由修改后热更新不生效,可能因为 routeTree.gen.ts 缓存。手动删除该文件并重启 dev server。