Отримання даних у Next.js
У маршрутизаторі додатка (App Router) отримання даних відбувається безпосередньо в серверних компонентах. Не потрібні спеціальні функції, такі як getServerSideProps або getStaticProps. Компонент просто await запит.
Отримання даних у серверних компонентах
// app/problems/page.tsx
import { db } from '@/lib/db'
export default async function ProblemsPage() {
const problems = await db.problem.findMany({
orderBy: { difficulty: 'asc' }
})
return (
<ul>
{problems.map(p => (
<li key={p.id}>{p.name}</li>
))}
</ul>
)
}Серверний компонент може безпосередньо отримувати доступ до бази даних, файлової системи або зовнішніх API. Код і залежності не включені до клієнтського бандлу.
fetch з кешуванням
Next.js розширює стандартний fetch, додаючи кешування та повторну валідацію:
// Кешується за замовчуванням (еквівалент SSG)
const res = await fetch('https://api.itlead.org/docs')
// Без кешування (еквівалент SSR)
const res = await fetch('https://api.itlead.org/feed', {
cache: 'no-store'
})
// Повторна валідація на основі часу (еквівалент ISR)
const res = await fetch('https://api.itlead.org/problems', {
next: { revalidate: 300 }
})
// Повторна валідація на основі тегів
const res = await fetch('https://api.itlead.org/problems', {
next: { tags: ['problems'] }
})Паралельне отримання даних
Звичайна помилка: послідовні запити, які могли б виконуватись паралельно.
// Погано: послідовні запити
export default async function DashboardPage() {
const user = await getUser()
const stats = await getStats() // чекає на getUser
const activity = await getActivity() // чекає на getStats
// ...
}
// Добре: паралельні запити
export default async function DashboardPage() {
const [user, stats, activity] = await Promise.all([
getUser(),
getStats(),
getActivity()
])
// ...
}Шаблон: Попереднє завантаження даних
Для паралельного завантаження на рівні дерева компонентів використовуйте шаблон попереднього завантаження:
// lib/problems.ts
import { cache } from 'react'
export const getProblems = cache(async () => {
const res = await fetch('https://api.itlead.org/problems')
return res.json()
})
export function preloadProblems() {
void getProblems()
}// app/problems/page.tsx
import { getProblems, preloadProblems } from '@/lib/problems'
import { ProblemList } from './problem-list'
export default async function ProblemsPage() {
preloadProblems()
return <ProblemList />
}React.cache гарантує, що запит виконується лише один раз, навіть якщо getProblems викликається в кількох місцях.
Отримання даних на стороні клієнта
Для інтерактивних сценаріїв (пошук, фільтрація) дані завантажуються на стороні клієнта:
'use client'
import { useEffect, useState } from 'react'
export function ProblemSearch() {
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
useEffect(() => {
if (!query) return
const controller = new AbortController()
fetch(`/api/search?q=${query}`, { signal: controller.signal })
.then(res => res.json())
.then(setResults)
return () => controller.abort()
}, [query])
return (
<div>
<input value={query} onChange={e => setQuery(e.target.value)} />
<ul>{results.map(r => <li key={r.id}>{r.name}</li>)}</ul>
</div>
)
}Практична порада:
Завантажуйте початкові дані на сервері та передавайте їх до клієнтських компонентів через пропси. Використовуйте отримання даних на стороні клієнта лише для даних, які залежать від дій користувача.
Корисні ресурси
- nextjs.org/docs — Отримання даних
- Шаблони отримання даних
Суміжні теми
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.