C
React/API Integration/Lesson 15

Data Fetching

30 min·theory
This chapter
1/2
JavaScript

Data Fetching

💡 Why Should You Learn This?

🎯 You can fetch real-time data from the server's database and display it on screen.
💼 Caching significantly improves app performance by reducing unnecessary requests.
It is an essential skill required in hiring at major companies like Naver and Coupang.
🏢 실무에서는
All real-time data — such as Coupang's product listings, Toss's account information, and Karrot Market's posts — is implemented through API data fetching. Without knowing efficient caching strategies, you cannot handle millions of users.

Concepts

The advanced caching and ISR (Incremental Static Regeneration) features available in Next.js 14+'s App Router are essential skills for modern web applications. They directly impact high-traffic handling and user experience optimization, and are evaluated as key performance metrics at major companies like Naver, Coupang, and Toss.

Why Does It Matter?

If you fetch frequently changing data — such as a commerce product listing — from the server on every request, response times can exceed 3 seconds, increasing bounce rates by 50%. For content that needs periodic updates but not real-time delivery, such as news sites or blogs, a well-chosen revalidate strategy can cut CDN costs by 70%.

Core Concept

Next.js data fetching works like a "smart refrigerator." Just as a fridge checks expiration dates and only replaces items that have gone bad, Next.js manages data "freshness" and only re-fetches stale data from the server. The fetch cache acts as the refrigerator that stores data, while revalidate acts as the sensor that checks expiration.

Key Points

  • fetch() caches data in two stages by default: Request Memoization and Data Cache
  • The revalidate option controls how often data freshness is checked (in seconds)
  • In App Router, combining generateStaticParams with revalidate enables optimization of dynamic routing as well
💻 Bad Example — Fetching Data Every Time Without Caching
// app/products/page.tsx - Anti-pattern
export default async function ProductsPage() {
  // Server request every time - slow and inefficient
  const res = await fetch('https://api.example.com/products', {
    cache: 'no-store' // Disable cache
  });
  const products = await res.json();

  return (
    <div>
      {products.map(product => (
        <div key={product.id}>{product.name}</div>
      ))}
    </div>
  );
}
💻 Good Example — Recommended Caching Strategy for 2025
// app/products/page.tsx - Optimized pattern
export default async function ProductsPage() {
  // Data refreshed every hour, cache used in between
  const res = await fetch('https://api.example.com/products', {
    next: { 
      revalidate: 3600, // 1 hour = 3600 seconds
      tags: ['products'] // Selective invalidation with cache tags
    }
  });
  const products = await res.json();

  return (
    <div>
      {products.map(product => (
        <div key={product.id}>{product.name}</div>
      ))}
    </div>
  );
}

// app/admin/actions.ts - Invalidate cache when admin updates product
'use server';
import { revalidateTag } from 'next/cache';

export async function updateProduct(formData: FormData) {
  // Product update logic...
  
  // Invalidate cache for specific tag only
  revalidateTag('products');
}
💻 Advanced Example — Optimization Combined with Dynamic Routing
// app/products/[id]/page.tsx
interface Props {
  params: { id: string };
}

// 100 popular products are pre-generated at build time
export async function generateStaticParams() {
  const products = await fetch('https://api.example.com/popular-products')
    .then(res => res.json());
  
  return products.map((product: any) => ({
    id: product.id.toString()
  }));
}

export default async function ProductPage({ params }: Props) {
  // Product details refreshed every 30 minutes
  const product = await fetch(`https://api.example.com/products/${params.id}`, {
    next: { 
      revalidate: 1800, // 30 minutes
      tags: [`product-${params.id}`]
    }
  }).then(res => res.json());

  return (
    <div>
      <h1>{product.name}</h1>
      <p>Price: {product.price} won</p>
    </div>
  );
}

💡 ⚠️ Common Mistakes

  • Setting the revalidate interval too short, negating the benefits of caching (values under 5 seconds are almost never necessary)
  • Not using cache tags, forcing you to invalidate the entire cache inefficiently (overusing revalidatePath)
  • Not combining generateStaticParams with revalidate, missing out on dynamic routing optimization

💡 🎯 Interview Prep

Q: Explain the difference between ISR and SSG in Next.js, and when you would use each.
Q: How would you design a Next.js caching strategy for high-traffic scenarios?
Q: Describe the difference between revalidateTag and revalidatePath and give usage scenarios for each.

Hint: Describe ISR as a hybrid approach that allows data updates even after the build, and support your answer with real-world examples (e.g., commerce product listings). Mentioning the differences between caching levels (Request Memoization vs. Data Cache) and the advantages of tag-based invalidation will earn you high marks.

⚛️ React Pattern — Data Fetching

Learn how data fetching is used in React step by step, with code examples.
1 🧩 1. When to Use Data Fetching
Situations where this feature is needed.
2 💻 2. Writing the Code
Basic usage of data fetching.
3 🎨 3. Rendered Output
What the user sees on screen.
4 💡 4. Practical Tips
Common pitfalls and best practices.

🎮 Data Fetching — Step-by-Step Understanding

Click each step to read the content, then mark your progress with the ✓ Got it button.
🖥️ Result — rendered React component
✏️ React 코드 수정하기 (클릭해서 열기)
⚛️ React 18 + Babel Standalone — see the result first, then edit the code yourself.

Check Quiz

Which Hook is the correct way to call an API when a component mounts in React?
💡 useEffect(fn, []) runs only once when the component first mounts. Side effects such as API calls and event listener registration should be handled inside useEffect. Calling them directly during rendering can cause an infinite loop.
Data Fetching - React