在开始从 React Location 迁移之前,重要的是您要充分理解 TanStack Router 所使用的路由概念和设计决策。
React Location 和 TanStack Router 共享许多相同的设计决策概念,但您应该注意一些关键区别。
在本指南中,我们将介绍使用基于文件的路由将 React Location 基本示例迁移到 TanStack Router 的过程,最终目标是实现与原始示例相同的功能(样式和其他非路由相关代码将被省略)。
提示
要使用基于代码的方法定义路由,您可以阅读基于代码的路由指南。
首先,我们需要安装 TanStack Router 的依赖项。有关详细安装说明,请参阅我们的如何安装 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>
)
}
您需要将帖子路由所需的任何相关组件和逻辑从 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,
})
您需要将帖子索引路由所需的任何相关组件和逻辑从 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()
// ...
}
您需要将帖子 ID 路由所需的任何相关组件和逻辑从 src/index.tsx 文件移动到 src/routes/posts.$postId.tsx 文件中。
如果您正在使用受支持的打包器之一,当您运行 dev 脚本时,路由树将自动生成。
如果您没有使用受支持的打包器之一,您可以通过运行以下命令来生成路由树
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 中寻求帮助。
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。