Capítulo 3 de 24

Chapter 3: Basic Routing (File-Based)

Core Idea

Builds past the quickstart into common real-world routing needs: nested routes with a loader (/posts/$postId), a pathless layout route (_pathlessLayout) that wraps children without adding to the URL, dynamic params, error components, and a root-level not-found component. This is the reference example for "how do I structure a real file-based app."

Setup

  • Routing style: file-based
  • Key dependencies: @tanstack/react-router, @tanstack/router-plugin, @tanstack/react-router-devtools, redaxios (data fetching), zod
  • Structure: src/routes/__root.tsx defines the shared layout, nav links, and a notFoundComponent. src/routes/_pathlessLayout.tsx (leading underscore) is a layout-only route with no URL segment of its own. src/routes/posts.$postId.tsx uses the $paramName filename convention for a dynamic segment and a loader to fetch data before render.

Code Example

// src/routes/posts.$postId.tsx
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params: { postId } }) => fetchPost(postId),
  errorComponent: PostErrorComponent,
  notFoundComponent: () => <p>Post not found</p>,
  component: PostComponent,
})

export function PostErrorComponent({ error }: ErrorComponentProps) {
  return <ErrorComponent error={error} />
}

function PostComponent() {
  const post = Route.useLoaderData()
  return (
    <div className="space-y-2">
      <h4 className="text-xl font-bold underline">{post.title}</h4>
      <div className="text-sm">{post.body}</div>
    </div>
  )
}
// src/routes/_pathlessLayout.tsx
export const Route = createFileRoute('/_pathlessLayout')({
  component: LayoutComponent,
})

function LayoutComponent() {
  return (
    <div className="p-2">
      <div className="border-b">I'm a pathless layout</div>
      <div><Outlet /></div>
    </div>
  )
}
  • What it demonstrates: $postId in a filename becomes params.postId in the loader; Route.useLoaderData() reads what the loader returned with full type inference; a leading-underscore filename (_pathlessLayout) creates a layout route that groups children under a shared UI without adding a path segment.

Key Takeaways

  1. Co-locate loader, errorComponent, and notFoundComponent on the route definition itself, TanStack Router calls them automatically during navigation, no manual try/catch in the component.
  2. Use a _layoutName file to share UI (e.g. a sidebar) across a group of routes when you don't want that grouping to appear in the URL.
  3. Route.useLoaderData() is the idiomatic way to read loader output; it's tied to that specific route's generated types, so renaming a param name updates the type everywhere.

Connects To

  • ch004-basic (code-based): the same posts/pathless-layout app, expressed with createRoute + .lazy() code splitting instead of files.
  • basic-ssr-file-based (not covered in depth here): extends this same posts/$postId pattern to server-side rendering; worth checking when a loader needs to run on the server.