kb.erickguedes.com
TanStack: Ecossistema de Bibliotecas

TanStack Router: Roteamento Type-First

Aula 2 de 5

Roteamento com TanStack Router

O TanStack Router é um roteador type-safe com suporte a file-based routing, loaders, componentes de loading/error e validação de parâmetros.

Configuração Inicial

npm create vite@latest router-demo -- --template react-ts
cd router-demo
npm install @tanstack/react-router

Estrutura de Rotas

// src/main.tsx — Provider e Router
import { RouterProvider, createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

const router = createRouter({ routeTree })

declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router
  }
}

function App() {
  return <RouterProvider router={router} />
}

createRootRoute e Layout

// src/routes/__root.tsx
import { createRootRoute, Outlet, Link } from '@tanstack/react-router'

export const Route = createRootRoute({
  component: () => (
    <div>
      <nav>
        <Link to="/" className="[&.active]:font-bold">Home</Link>
        <Link to="/dashboard" activeProps={{ className: 'font-bold' }}>Dashboard</Link>
      </nav>
      <hr />
      <Outlet /> {/* Renderiza o conteúdo da rota filha */}
    </div>
  ),
})

Rotas com Parâmetros

// src/routes/users.$userId.tsx
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/users/$userId')({
  component: UserProfile,
  loader: async ({ params }) => {
    const user = await fetch(`/api/users/${params.userId}`).then(r => r.json())
    return { user }
  },
  pendingComponent: () => <div>Carregando...</div>,
  errorComponent: ({ error }) => <div>Erro: {error.message}</div>,
})

function UserProfile() {
  const { user } = Route.useLoaderData()
  const { userId } = Route.useParams()
  return <div>{user.name}</div>
}

Search Params com Validação

// src/routes/users/index.tsx
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'

const searchSchema = z.object({
  page: z.number().default(1),
  search: z.string().optional(),
  sort: z.enum(['name', 'date']).default('name'),
})

export const Route = createFileRoute('/users/')({
  validateSearch: (search: Record<string, unknown>) => searchSchema.parse(search),
  component: UserList,
})

function UserList() {
  const { page, search, sort } = Route.useSearch()
  const navigate = Route.useNavigate()

  return (
    <div>
      <input
        value={search}
        onChange={e => navigate({ search: { search: e.target.value, page: 1 } })}
      />
      <UsersTable page={page} search={search} sort={sort} />
    </div>
  )
}

Route Guards e Redirect

export const Route = createFileRoute('/dashboard')({
  beforeLoad: async ({ location }) => {
    const token = localStorage.getItem('token')
    if (!token) {
      throw redirect({ to: '/login', search: { redirect: location.href } })
    }
  },
  component: Dashboard,
})

Navegação Programática

// useNavigate hook
const navigate = useNavigate()

navigate({ to: '/users/$userId', params: { userId: '123' } })
navigate({ to: '/', search: { q: 'termo' } })
navigate({ to: '.', search: { page: current + 1 } }) // relativo

Lab: Aplicação Multi-rota

npm create vite@latest router-app -- --template react-ts
cd router-app
npm install @tanstack/react-router
npx tsr generate
// Crie:
// 1. Rota raiz com layout e navegação
// 2. /products com search params (paginação, filtro)
// 3. /products/$productId com loader assíncrono
// 4. Rota protegida /admin com beforeLoad guard
// 5. Componente pending e error para cada rota

O TanStack Router oferece type-safety total entre links, parâmetros e loaders, eliminando inconsistências comuns em roteadores tradicionais.