Next.js 15 From Scratch

Ders 7/8 30 dakika

Static and Dynamic Data Fetching

Fetching data with async/await inside Server Components, the difference between static and dynamic rendering, and ISR with revalidate.

Data Fetching in Server Components

Next.js 15's most powerful feature: Server Components can be async functions. You can connect directly to databases or APIs — nothing runs in the browser, the code stays on the server.

// app/blog/page.tsx — This is a Server Component
export default async function BlogList() {
  // This runs on the SERVER — API keys stay safe
  const response = await fetch("https://api.example.com/posts");
  const posts = await response.json();

  return (
    <div>
      {posts.map((post: any) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

Static vs Dynamic Rendering

ModeDescriptionWhen?
StaticRendered at build time, cached on CDNBlog, landing pages, static content
DynamicRendered on each request on the serverDashboard, user-specific content
ISRRegenerated at a set intervalNews sites, price lists

Cache Control

// 1. Static — cached at build time (default)
const data = await fetch("https://api.com/data");

// 2. Dynamic — NO cache, fetched on every request
const data = await fetch("https://api.com/data", {
  cache: "no-store",
});

// 3. ISR — revalidate every 60 seconds
const data = await fetch("https://api.com/data", {
  next: { revalidate: 60 },
});

Parallel Data Fetching

export default async function Dashboard() {
  // ✅ Parallel — they don't wait for each other
  const [user, orders, stats] = await Promise.all([
    fetch("/api/user").then(r => r.json()),
    fetch("/api/orders").then(r => r.json()),
    fetch("/api/stats").then(r => r.json()),
  ]);

  return <div>...</div>;
}

Skeleton Loading with loading.tsx

// app/blog/loading.tsx
export default function Loading() {
  return (
    <div className="space-y-4">
      {[...Array(3)].map((_, i) => (
        <div key={i} className="animate-pulse">
          <div className="h-6 bg-gray-200 rounded w-3/4 mb-2"></div>
          <div className="h-4 bg-gray-200 rounded w-1/2"></div>
        </div>
      ))}
    </div>
  );
}

Önemli Noktalar

  • Server Components can be async — use await directly
  • Control cache with no-store (dynamic) or revalidate (ISR)
  • Use Promise.all for parallel fetching — never fetch serially
  • loading.tsx creates an automatic Suspense boundary