自动
框架
版本

从 React Location 迁移

在开始从 React Location 迁移的旅程之前,重要的是您对 TanStack Router 使用的 路由概念设计决策 有很好的理解。

React Location 和 TanStack Router 之间的差异

React Location 和 TanStack Router 在很大程度上共享相同的设计决策概念,但您应该注意一些关键差异。

  • React Location 使用泛型来推断路由的类型,而 TanStack Router 使用模块声明合并来推断类型。
  • React Location 中的路由配置是使用单个路由定义数组完成的,而在 TanStack Router 中,路由配置是使用从根路由开始的路由定义树完成的。
  • 基于文件的路由是在 TanStack Router 中定义路由的推荐方式,而 React Location 仅允许您使用基于代码的方法在单个文件中定义路由。

迁移指南

在本指南中,我们将介绍将 React Location Basic 示例 使用基于文件的路由迁移到 TanStack Router 的过程,最终目标是拥有与原始示例相同的功能(样式和其他非路由相关代码将被省略)。

提示

要使用基于代码的方法来定义路由,您可以阅读基于代码的路由指南。

步骤 1:切换到 TanStack Router 的依赖项

首先,我们需要安装 TanStack Router 的依赖项。

sh
npm install @tanstack/react-router @tanstack/router-devtools
npm install @tanstack/react-router @tanstack/router-devtools

并删除 React Location 依赖项。

sh
npm uninstall @tanstack/react-location @tanstack/react-location-devtools
npm uninstall @tanstack/react-location @tanstack/react-location-devtools

步骤 2:使用基于文件的路由监听器

如果您的项目使用 Vite(或受支持的 bundler 之一),您可以使用 TanStack Router 插件来监视路由文件中的更改并自动更新路由配置。

Vite 插件的安装

sh
npm install -D @tanstack/router-plugin
npm install -D @tanstack/router-plugin

并将其添加到您的 vite.config.js

js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'

export default defineConfig({
  // ...
  plugins: [TanStackRouterVite(), react()],
})
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'

export default defineConfig({
  // ...
  plugins: [TanStackRouterVite(), react()],
})

但是,如果您的应用程序不使用 Vite,您可以使用我们的其他受支持的 bundler之一,或者您可以使用 @tanstack/router-cli 包来监视路由文件中的更改并自动更新路由配置。

步骤 3:将基于文件的配置文件添加到您的项目

在您的项目根目录中创建一个 tsr.config.json 文件,内容如下

json
{
  "routesDirectory": "./src/routes",
  "generatedRouteTree": "./src/routeTree.gen.ts"
}
{
  "routesDirectory": "./src/routes",
  "generatedRouteTree": "./src/routeTree.gen.ts"
}

您可以在此处找到 tsr.config.json 文件的完整选项列表。

步骤 4:创建 routes 目录

在您的项目的 src 目录中创建一个 routes 目录。

sh
mkdir src/routes
mkdir src/routes

步骤 5:创建根路由文件

tsx
// 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 />
      </>
    )
  },
})

步骤 6:创建索引路由文件

tsx
// 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 文件。

步骤 7:创建 posts 路由文件

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 文件。

步骤 8:创建 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 文件。

步骤 9:创建 posts id 路由文件

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 文件。

步骤 10:生成路由树

如果您使用的是受支持的 bundler 之一,则在您运行开发脚本时将自动生成路由树。

如果您没有使用受支持的 bundler 之一,则可以通过运行以下命令来生成路由树

sh
npx tsr generate
npx tsr generate

步骤 11:更新主入口文件以渲染 Router

生成路由树后,您可以更新 src/index.tsx 文件以创建 router 实例并渲染它。

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 中寻求帮助。

订阅 Bytes

您的每周 JavaScript 新闻。每周一免费发送给超过 100,000 名开发人员。

Bytes

无垃圾邮件。随时取消订阅。