在开始从 React Location 迁移之前,重要的是您要对 TanStack Router 使用的路由概念和设计决策有良好的理解。
React Location 和 TanStack Router 共享许多相同的设计决策概念,但有一些您应该了解的关键差异。
在本指南中,我们将介绍使用基于文件的路由将 React Location Basic 示例迁移到 TanStack Router 的过程,最终目标是具有与原始示例相同的功能(将省略样式和其他非路由相关代码)。
Tip
要使用基于代码的方法来定义您的路由,您可以阅读基于代码的路由指南。
首先,我们需要安装 TanStack Router 的依赖项。
npm install @tanstack/react-router @tanstack/router-devtools
npm install @tanstack/react-router @tanstack/router-devtools
并移除 React Location 依赖项。
npm uninstall @tanstack/react-location @tanstack/react-location-devtools
npm uninstall @tanstack/react-location @tanstack/react-location-devtools
如果您的项目使用 Vite(或支持的打包器之一),您可以使用 TanStack Router 插件来监视路由文件的更改并自动更新路由配置。
安装 Vite 插件:
npm install -D @tanstack/router-plugin
npm install -D @tanstack/router-plugin
并将其添加到您的 vite.config.js:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
// ...
plugins: [tanstackRouter(), react()],
})
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
// ...
plugins: [tanstackRouter(), react()],
})
但是,如果您的应用程序不使用 Vite,您可以使用我们其他的支持的打包器之一,或者您可以使用 @tanstack/router-cli 包来监视路由文件的更改并自动更新路由配置。
在项目根目录中创建一个 tsr.config.json 文件,内容如下:
{
"routesDirectory": "./src/routes",
"generatedRouteTree": "./src/routeTree.gen.ts"
}
{
"routesDirectory": "./src/routes",
"generatedRouteTree": "./src/routeTree.gen.ts"
}
您可以在这里找到 tsr.config.json 文件的完整选项列表。
在项目的 src 目录中创建一个 routes 目录。
mkdir src/routes
mkdir src/routes
// src/routes/__root.tsx
import { createRootRoute, Outlet, Link } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
export const Route = createRootRoute({
component: () => {
return (
<>
<div>
<Link to="/" activeOptions={{ exact: true }}>
Home
</Link>
<Link to="/posts">Posts</Link>
</div>
<hr />
<Outlet />
<TanStackRouterDevtools />
</>
)
},
})
// src/routes/__root.tsx
import { createRootRoute, Outlet, Link } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
export const Route = createRootRoute({
component: () => {
return (
<>
<div>
<Link to="/" activeOptions={{ exact: true }}>
Home
</Link>
<Link to="/posts">Posts</Link>
</div>
<hr />
<Outlet />
<TanStackRouterDevtools />
</>
)
},
})
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: Index,
})
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: Index,
})
您需要将索引路由所需的任何相关组件和逻辑从 src/index.tsx 文件移动到 src/routes/index.tsx 文件。
// src/routes/posts.tsx
import { createFileRoute, Link, Outlet } from '@tanstack/react-router'
export const Route = createFileRoute('/posts')({
component: Posts,
loader: async () => {
const posts = await fetchPosts()
return {
posts,
}
},
})
function Posts() {
const { posts } = Route.useLoaderData()
return (
<div>
<nav>
{posts.map((post) => (
<Link
key={post.id}
to={`/posts/$postId`}
params={{ postId: post.id }}
>
{post.title}
</Link>
))}
</nav>
<Outlet />
</div>
)
}
// src/routes/posts.tsx
import { createFileRoute, Link, Outlet } from '@tanstack/react-router'
export const Route = createFileRoute('/posts')({
component: Posts,
loader: async () => {
const posts = await fetchPosts()
return {
posts,
}
},
})
function Posts() {
const { posts } = Route.useLoaderData()
return (
<div>
<nav>
{posts.map((post) => (
<Link
key={post.id}
to={`/posts/$postId`}
params={{ postId: post.id }}
>
{post.title}
</Link>
))}
</nav>
<Outlet />
</div>
)
}
您需要将 posts 路由所需的任何相关组件和逻辑从 src/index.tsx 文件移动到 src/routes/posts.tsx 文件。
// src/routes/posts.index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/')({
component: PostsIndex,
})
// src/routes/posts.index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/')({
component: PostsIndex,
})
您需要将 posts 索引路由所需的任何相关组件和逻辑从 src/index.tsx 文件移动到 src/routes/posts.index.tsx 文件。
// src/routes/posts.$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
component: PostsId,
loader: async ({ params: { postId } }) => {
const post = await fetchPost(postId)
return {
post,
}
},
})
function PostsId() {
const { post } = Route.useLoaderData()
// ...
}
// src/routes/posts.$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
component: PostsId,
loader: async ({ params: { postId } }) => {
const post = await fetchPost(postId)
return {
post,
}
},
})
function PostsId() {
const { post } = Route.useLoaderData()
// ...
}
您需要将 posts id 路由所需的任何相关组件和逻辑从 src/index.tsx 文件移动到 src/routes/posts.$postId.tsx 文件。
如果您使用支持的打包器之一,路由树将在您运行开发脚本时自动生成。
如果您不使用支持的打包器之一,您可以通过运行以下命令来生成路由树:
npx tsr generate
npx tsr generate
生成路由树后,您可以更新 src/index.tsx 文件来创建路由器实例并渲染它。
// src/index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { createRouter, RouterProvider } from '@tanstack/react-router'
// Import the generated route tree
import { routeTree } from './routeTree.gen'
// 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
}
}
const domElementId = 'root' // Assuming you have a root element with the id 'root'
// Render the app
const rootElement = document.getElementById(domElementId)
if (!rootElement) {
throw new Error(`Element with id ${domElementId} not found`)
}
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
// src/index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { createRouter, RouterProvider } from '@tanstack/react-router'
// Import the generated route tree
import { routeTree } from './routeTree.gen'
// 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
}
}
const domElementId = 'root' // Assuming you have a root element with the id 'root'
// Render the app
const rootElement = document.getElementById(domElementId)
if (!rootElement) {
throw new Error(`Element with id ${domElementId} not found`)
}
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
您现在应该已经成功地使用基于文件的路由将您的应用程序从 React Location 迁移到 TanStack Router。
React Location 还有一些您可能在应用程序中使用的其他功能。以下是一些帮助您迁移这些功能的指南:
TanStack Router 还有一些您可能想要探索的其他功能:
如果您遇到任何问题或有任何疑问,请随时在 TanStack Discord 中寻求帮助。