Capítulo 14 de 57

Chapter 14: Migrate from React Location

Core Idea

Migrating from React Location (TanStack Router's spiritual predecessor, sharing many design decisions) follows a concrete step-by-step recipe: swap dependencies, set up file-based route generation via the Vite plugin or CLI, and recreate the app's route files (__root.tsx, index.tsx, posts.tsx, posts.index.tsx, posts.$postId.tsx) one at a time before wiring the router instance into the entry file.

Key Concepts

  • Core type-inference difference: React Location uses generics to infer route types, while TanStack Router uses module declaration merging (declare module '@tanstack/react-router' { interface Register { router: typeof router } }).
  • Route configuration structure difference: React Location configures routes as a single flat array; TanStack Router builds a tree of route definitions starting from the root route.
  • File-based routing as the default: Unlike React Location (code-based only, single file), TanStack Router recommends file-based routing; code-based routing is supported but not preferred (see Ch 4 for why).
  • tsr.config.json: Minimal config { "routesDirectory": "./src/routes", "generatedRouteTree": "./src/routeTree.gen.ts" } needed when not relying purely on bundler-plugin defaults.
  • Nested route file naming: posts.tsx (layout with loader + Outlet), posts.index.tsx (the /posts/ index child), and posts.$postId.tsx (dynamic child with its own loader) demonstrate the flat-file naming convention for nested routes.
  • Route.useLoaderData(): The pattern for accessing loader-fetched data inside a route's component, shown in the posts.tsx and posts.$postId.tsx examples.

Code Examples

// 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()
  // ...
}
  • What it demonstrates: A dynamic child route with a typed loader reading params.postId and exposing its result via Route.useLoaderData().

Key Takeaways

  1. The migration is largely mechanical: replace @tanstack/react-location(-devtools) with @tanstack/react-router(-devtools), add @tanstack/router-plugin, create a routes/ directory, and rebuild each route as its own file.
  2. TanStack Router's flat dotted file-naming convention (posts.tsx, posts.index.tsx, posts.$postId.tsx) maps directly onto React Location's single-array route config, just split across files.
  3. After migrating, worthwhile TanStack Router features not present in React Location include Router Context, Preloading, Pathless Layout Routes, Route Masking, and SSR support, all worth exploring post-migration.

Connects To

  • Ch 4: Decisions on DX is required reading before this migration per the docs, it explains the module-declaration and file-based routing choices referenced here.
  • Ch 13: Migrate from React Router covers the analogous migration path from React Router/Remix.
  • Ch 8: With Vite details the plugin setup step used partway through this migration.