Learning
Next.js

Adatlekérés (fetch, Server Actions)

A legegyszerűbb és leghatékonyabb módszer: async Server Component:

6. Adatlekérés (fetch, Server Actions)

Server oldali adatlekérés

A legegyszerűbb és leghatékonyabb módszer: async Server Component:

// app/products/page.tsx
async function getProducts() {
  const res = await fetch('https://api.example.com/products', {
    next: { revalidate: 3600 }, // ISR: 1 óránként frissül
  })

  if (!res.ok) throw new Error('Fetch sikertelen')
  return res.json()
}

export default async function ProductsPage() {
  const products = await getProducts()

  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  )
}

Cache opciók fetch-nél

// Statikus – build időben egyszer lekéri, cache-eli
fetch(url, { cache: 'force-cache' })

// Dinamikus – minden kérésnél frissen lekéri
fetch(url, { cache: 'no-store' })

// ISR – megadott időnként frissül
fetch(url, { next: { revalidate: 60 } }) // 60 másodpercenként

// Tag alapú revalidálás
fetch(url, { next: { tags: ['products'] } })

Server Actions

A Server Actions szerveren futó függvények, amelyeket kliens komponensekből lehet meghívni – form submission, mutation, stb.

// app/actions.ts
'use server'

import { revalidateTag } from 'next/cache'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string

  // Adatbázis írás
  await db.posts.create({ title, content })

  // Cache invalidálás
  revalidateTag('posts')
}
// app/new-post/page.tsx – Server Component
import { createPost } from '@/app/actions'

export default function NewPostPage() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Cím" required />
      <textarea name="content" placeholder="Tartalom" required />
      <button type="submit">Közzétesz</button>
    </form>
  )
}

Server Action Client Component-ből

'use client'

import { useTransition } from 'react'
import { createPost } from '@/app/actions'

export default function NewPostForm() {
  const [isPending, startTransition] = useTransition()

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    const formData = new FormData(e.currentTarget)
    startTransition(async () => {
      await createPost(formData)
    })
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="title" placeholder="Cím" />
      <button type="submit" disabled={isPending}>
        {isPending ? 'Mentés...' : 'Közzétesz'}
      </button>
    </form>
  )
}

Párhuzamos adatlekérés

export default async function DashboardPage() {
  // ❌ Szekvenciális – lassú
  const user = await fetchUser()
  const posts = await fetchPosts()

  // ✅ Párhuzamos – gyors
  const [user, posts] = await Promise.all([
    fetchUser(),
    fetchPosts(),
  ])

  return <Dashboard user={user} posts={posts} />
}

Loading UI és Suspense

// app/blog/loading.tsx – automatikusan megjelenik adatlekérés alatt
export default function Loading() {
  return <div className="animate-pulse">Betöltés...</div>
}
// Manuális Suspense – granulálisabb control
import { Suspense } from 'react'

export default function Page() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<Skeleton />}>
        <SlowDataComponent />
      </Suspense>
    </div>
  )
}

📝 Összefoglaló – 6. fejezet

  • Server Component-ekben async/await-tel közvetlenül lekérhetsz adatot, nincs szükség useEffect-re
  • A fetch API kiterjesztve cache opciókkal: force-cache, no-store, revalidate
  • Server Actions szerveren futó mutációkat tesznek lehetővé form-okból és Client Componentekből
  • A Promise.all párhuzamosítja az adatlekéréseket – mindig ezt használd, ha lehetséges
  • A vízesések elkerülése, a Suspense és a React.cache() részletesen a következő fejezetben van

On this page