Skip to content

Ders 02: Routing - Temel Seviye

  • File-based routing sistemi nasıl çalışır?
  • Yeni sayfalar/route’lar nasıl oluşturulur?
  • Route parametreleri nasıl kullanılır?
  • Link bileşeniyle sayfalar arası geçiş nasıl yapılır?
  • Route’lar arası veri paylaşımı (nested routes)

TanStack Start, TanStack Router kullanarak file-based routing sunar. Bu, dosya sisteminizdeki yapının doğrudan URL yapısına karşılık geldiği anlamına gelir.

KavramAçıklama
File-based routingDosya yolu URL’ye dönüşür
RouteBelirli bir URL’e karşılık gelen sayfa
Nested routesİç içe geçmiş route’lar
Route paramsURL’den dinamik veri alma (:id gibi)
OutletÇocuk route’ları render eden bileşen

Hadi hakkimizda sayfası oluşturalım!

src/routes/hakkimizda.tsx
src/routes/hakkimizda.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hakkimizda')({
component: HakkimizdaPage,
})
function HakkimizdaPage() {
return (
<div style={{ padding: '2rem' }}>
<h1>Hakkımızda</h1>
<p>Biz TanStack Start öğreniyoruz!</p>
<p>Bu kurs, modern React geliştirme üzerine odaklanmıştır.</p>
</div>
)
}

Şimdi tarayıcıda http://localhost:3000/hakkimizda adresine gidin.

Dikkat: Dosya ismi ve createFileRoute içindeki path aynı olmalıdır!

Dosya YoluURLAçıklama
src/routes/index.tsx/Ana sayfa
src/routes/hakkimizda.tsx/hakkimizdaHakkımızda
src/routes/iletisim.tsx/iletisimİletişim
src/products.tsx/productsProducts
src/products/index.tsx/productsProducts (alternatif)

TanStack Start, kendi Link bileşenini sunar. Bu bileşen type-safe’tir ve navigasyon optimize eder.

import { createFileRoute, Link } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: HomePage,
})
function HomePage() {
return (
<div>
<h1>Ana Sayfa</h1>
<nav>
<ul style={{ display: 'flex', gap: '1rem', listStyle: 'none' }}>
<li>
<Link to="/hakkimizda">Hakkımızda</Link>
</li>
<li>
<Link to="/iletisim">İletişim</Link>
</li>
<li>
<Link to="/urunler">Ürünler</Link>
</li>
</ul>
</nav>
<p>Ana sayfa içeriği buraya...</p>
</div>
)
}

Aktif link’i stillemek için activeProps kullanabilirsiniz:

function Navigation() {
return (
<nav>
<ul style={{ display: 'flex', gap: '1rem', listStyle: 'none' }}>
<li>
<Link
to="/"
activeProps={{ style: { color: 'blue', fontWeight: 'bold' } }}
>
Ana Sayfa
</Link>
</li>
<li>
<Link
to="/hakkimizda"
activeProps={{ style: { color: 'blue', fontWeight: 'bold' } }}
>
Hakkımızda
</Link>
</li>
</ul>
</nav>
)
}

E-commerce sitesi düşünün: her ürünün kendi sayfası olmalı. URL şöyle olmalı: /urunler/urun-1, /urunler/urun-2, vb.

Terminal window
# src/routes/urunler/$urunId.tsx

$ işareti, bu kısmın dinamik olduğunu gösterir.

// src/routes/urunler/$urunId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/urunler/$urunId')({
component: UrunDetayPage,
})
function UrunDetayPage() {
// URL parametresine eriş
const { urunId } = Route.useParams()
return (
<div style={{ padding: '2rem' }}>
<h1>Ürün Detayı</h1>
<p>Ürün ID: <strong>{urunId}</strong></p>
<p>Bu ürünün detayları yakında buraya gelecek...</p>
</div>
)
}

Şimdi bu sayfaya gidin:

  • /urunler/urun-1 → “Ürün ID: urun-1”
  • /urunler/abc-123 → “Ürün ID: abc-123”
Terminal window
# src/routes/kategoriler/$kategoriId/urunler/$urunId.tsx
export const Route = createFileRoute('/kategoriler/$kategoriId/urunler/$urunId')({
component: UrunInKategoriPage,
})
function UrunInKategoriPage() {
const { kategoriId, urunId } = Route.useParams()
return (
<div>
<h1>Ürün: {urunId}</h1>
<p>Kategori: {kategoriId}</p>
</div>
)
}

URL: /kategoriler/elektronik/urunler/laptop-123

---
## 🌳 Nested Routing (İç İçe Route'lar)
Nested routing, bir route'un içinde başka bir route'un çalışmasıdır. Bu, layout'ları paylaşmak için harika bir yöntemdir!
### Layout Route Oluşturma
```bash
# src/routes/dashboard.tsx (Layout)
# src/routes/dashboard/index.tsx (Ana sayfa)
# src/routes/dashboard/ayarlarr.tsx (Ayarlar sayfası)

Dashboard Layout (dashboard.tsx):

src/routes/dashboard.tsx
import { createFileRoute, Outlet, Link } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard')({
component: DashboardLayout,
})
function DashboardLayout() {
return (
<div style={{ display: 'flex', minHeight: '100vh' }}>
{/* Sidebar */}
<aside style={{
width: '250px',
backgroundColor: '#f3f4f6',
padding: '1rem'
}}>
<h2>Dashboard</h2>
<nav>
<ul style={{ listStyle: 'none', padding: 0 }}>
<li style={{ marginBottom: '0.5rem' }}>
<Link to="/dashboard">Ana Sayfa</Link>
</li>
<li style={{ marginBottom: '0.5rem' }}>
<Link to="/dashboard/ayarlarr">Ayarlar</Link>
</li>
<li style={{ marginBottom: '0.5rem' }}>
<Link to="/dashboard/profil">Profil</Link>
</li>
</ul>
</nav>
</aside>
{/* Main Content - Çocuk route'lar buraya render edilir */}
<main style={{ flex: 1, padding: '2rem' }}>
<Outlet />
</main>
</div>
)
}

Dashboard Ana Sayfa (dashboard/index.tsx):

src/routes/dashboard/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard/')({
component: DashboardHome,
})
function DashboardHome() {
return (
<div>
<h1>Dashboard Ana Sayfa</h1>
<p>Dashboard'a hoş geldiniz!</p>
</div>
)
}

Dashboard Ayarlar (dashboard/ayarlarr.tsx):

src/routes/dashboard/ayarlarr.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard/ayarlarr')({
component: AyarlarrPage,
})
function AyarlarrPage() {
return (
<div>
<h1>Ayarlar</h1>
<p>İşte ayarlar sayfanız...</p>
</div>
)
}
/dashboard → DashboardLayout (sidebar + outlet)
├── /dashboard/ → DashboardHome
├── /dashboard/ayarlarr → AyarlarrPage
└── /dashboard/profil → ProfilPage

💡 Önemli: dashboard.tsx’de <Outlet /> bileşeni, çocuk route’ların nerede render edileceğini belirler.


Bazen JavaScript ile navigasyon yapmanız gerekir.

import { createFileRoute } from '@tanstack/react-router'
import { useNavigate } from '@tanstack/react-router'
export const Route = createFileRoute('/form')({
component: FormPage,
})
function FormPage() {
const navigate = useNavigate()
const handleSubmit = () => {
// Form gönderildiğinde ana sayfaya git
navigate({ to: '/' })
}
const goBack = () => {
// Bir sayfa geri git
navigate({ to: '..' })
}
return (
<div>
<h1>Form Sayfası</h1>
<button onClick={handleSubmit}>Gönder ve Ana Sayfaya Git</button>
<button onClick={goBack}>Geri</button>
</div>
)
}
// Basit navigasyon
navigate({ to: '/hakkimizda' })
// Bir sayfa geri
navigate({ to: '..' })
// İki sayfa ileri
navigate({ to: '../sibling' })
// Query param ile navigasyon
navigate({
to: '/arama',
search: { q: 'tanstack' }
})
// Replace (geçmişe eklemez)
navigate({
to: '/login',
replace: true
})

Hadi öğrendiklerimizi bir blog uygulamasıyla pekiştirelim!

/
├── blog.tsx (Layout - ortak header/footer)
│ ├── index.tsx (Blog listesi)
│ └── $slug.tsx (Blog detay)

Blog Layout (blog.tsx):

src/routes/blog.tsx
import { createFileRoute, Outlet, Link } from '@tanstack/react-router'
export const Route = createFileRoute('/blog')({
component: BlogLayout,
})
function BlogLayout() {
return (
<div>
{/* Ortak Header */}
<header style={{
backgroundColor: '#3b82f6',
color: 'white',
padding: '1rem 2rem',
marginBottom: '2rem'
}}>
<Link to="/" style={{ color: 'white', textDecoration: 'none' }}>
📝 Blogum
</Link>
<span style={{ marginLeft: '2rem' }}>
<Link to="/blog" style={{ color: 'white', textDecoration: 'none' }}>
Yazılar
</Link>
</span>
</header>
{/* Blog İçeriği */}
<main style={{ maxWidth: '800px', margin: '0 auto', padding: '0 1rem' }}>
<Outlet />
</main>
{/* Ortak Footer */}
<footer style={{
marginTop: '3rem',
padding: '2rem',
backgroundColor: '#f3f4f6',
textAlign: 'center'
}}>
<p>© 2025 Blogum - Tüm hakları saklıdır.</p>
</footer>
</div>
)
}

Blog Liste (blog/index.tsx):

src/routes/blog/index.tsx
import { createFileRoute, Link } from '@tanstack/react-router'
const YAZILAR = [
{ slug: 'tanstack-starta-giris', title: 'TanStack Start\'a Giriş', excerpt: 'Modern React framework' },
{ slug: 'routing-nedir', title: 'Routing Nedir?', excerpt: 'File-based routing sistemi' },
{ slug: 'server-functions', title: 'Server Functions', excerpt: 'Type-safe RPC' },
]
export const Route = createFileRoute('/blog/')({
component: BlogListe,
})
function BlogListe() {
return (
<div>
<h1 style={{ fontSize: '2rem', marginBottom: '2rem' }}>Yazılar</h1>
{YAZILAR.map((yazi) => (
<article
key={yazi.slug}
style={{
border: '1px solid #e5e7eb',
borderRadius: '8px',
padding: '1.5rem',
marginBottom: '1.5rem'
}}
>
<Link
to={`/blog/${yazi.slug}`}
style={{ textDecoration: 'none', color: 'inherit' }}
>
<h2 style={{ fontSize: '1.5rem', marginBottom: '0.5rem' }}>
{yazi.title}
</h2>
<p style={{ color: '#6b7280' }}>{yazi.excerpt}</p>
</Link>
</article>
))}
</div>
)
}

Blog Detay (blog/$slug.tsx):

// src/routes/blog/$slug.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/blog/$slug')({
component: BlogDetay,
})
function BlogDetay() {
const { slug } = Route.useParams()
return (
<article>
<h1>Yazı Detayı: {slug}</h1>
<p>Bu yazı için detaylı içerik yakında buraya gelecek...</p>
<Link to="/blog">← Listeye Dön</Link>
</article>
)
}

Bu derste öğrendiklerimiz:

KonuAçıklama
File-based routingDosya yolu URL’ye dönüşür
Statik routeSabit URL’li sayfa (hakkimizda.tsx)
Dinamik routeParametreli URL ($param)
LinkSayfalar arası geçiş bileşeni
useParamsRoute parametrelerini alma
OutletNested routing için çocuk render alanı
useNavigateProgramatik navigasyon
Nested routesİç içe route’lar, layout paylaşımı

Kişisel portföyö siteniz için şu sayfaları oluşturun:

  • / - Ana sayfa
  • /hakkimda - Hakkımda sayfası
  • /projeler - Projeler listesi
  • /projeler/$id - Proje detay sayfası

İpucu: Layout kullanarak ortak bir header/footer tasarlayın.

Bir e-ticaret sitesi kategorileri oluşturun:

/
├── shop.tsx (Layout)
│ ├── index.tsx (Tüm ürünler)
│ ├── elektronik.tsx
│ ├── giyim.tsx
│ └── $kategori/$urun.tsx (Ürün detay)

Navigasyon bileşeni oluşturun ki:

  • Aktif sayfa linki kalın ve mavi olsun
  • Aktif olmayan linkler normal görünsün
  • Hover efekti ekleyin

Bir sonraki derste şunları öğreneceksiniz:

  • 🔍 Search params ile arama yapma
  • 📦 Data loading ve loader fonksiyonları
  • ⏳ Loading ve error states
  • 🔄 Data revalidation ve caching
  • 🎯 Redirects ve 404 handling

  1. Nested routing’de Outlet zorunlu mu?
  2. Birden fazla dinamik parametre kullanabilir miyiz?
  3. Link vs normal <a> tag farkı nedir?

Bir sonraki derste görüşmek üzere! 👋