Skip to main content
Практика завдань

Ключові особливості Next.js

В інтерв'ю це питання перевіряє, наскільки глибоко ви знаєте фреймворк, а не лише те, що ви про нього чули. Недостатньо просто перерахувати "SSR, маршрутизація, оптимізація". Вам потрібно зрозуміти, як працює кожна функція і чому вона існує.

Давайте розглянемо основні функції Next.js по черзі.

Гібридний рендеринг

Основна сила Next.js полягає в тому, що ви самі обираєте стратегію рендерингу для кожної сторінки. Різні сторінки в одному додатку можуть використовувати різні підходи:

  • SSG статичний, генерується під час збірки. Для сторінок, які рідко змінюються.
  • SSR рендериться на сервері при кожному запиті. Для динамічного контенту.
  • ISR статичний з фоновою перевіркою. Компроміс між SSG і SSR.
  • CSR рендеринг на стороні клієнта, як у звичайному додатку React.
tsx
// Сторінка "Про нас" на IT Lead — статична (SSG за замовчуванням) export default async function AboutPage() { const info = await fetch('https://api.itlead.org/about') const data = await info.json() return <About data={data} /> }
tsx
// Потік проблем — оновлюється кожні 5 хвилин (ISR) export default async function ProblemsPage() { const res = await fetch('https://api.itlead.org/problems', { next: { revalidate: 300 } }) const problems = await res.json() return <ProblemList problems={problems} /> }

Порада для інтерв'ю:

Звичайне запитання: "Коли б ви обрали SSR замість SSG?". Гарна відповідь: SSR для сторінок з персоналізованим контентом (профіль, інформаційна панель), SSG для контенту, який однаковий для всіх (блог, документація).

App Router і маршрутизація на основі файлів

Починаючи з версії 13, Next.js використовує App Router. Структура папок всередині каталогу app безпосередньо визначає ваші маршрути:

  • app

  • layout.tsx

  • page.tsx

  • docs

  • page.tsx

  • [slug]

  • page.tsx

  • problems

  • page.tsx

  • loading.tsx

  • error.tsx

Кожна папка є сегментом URL. Спеціальні файли мають конкретні ролі:

ФайлПризначення
page.tsxUI сторінки
layout.tsxСпільний обгортка для сторінки та вкладених маршрутів
loading.tsxUI завантаження (працює з Suspense)
error.tsxUI помилки (працює з Error Boundary)
not-found.tsx404 UI
tsx
// app/docs/[slug]/page.tsx // Динамічний маршрут: /docs/javascript, /docs/react тощо. export default async function DocPage({ params }: { params: { slug: string } }) { const doc = await getDocument(params.slug) return <article>{doc.content}</article> }

Серверні компоненти

У App Router компоненти за замовчуванням є серверними компонентами. Це означає:

  • Вони виконуються лише на сервері
  • Їхній код не включається в пакет для клієнта
  • Вони можуть безпосередньо отримувати доступ до бази даних, файлової системи, змінних середовища
tsx
// Серверний компонент — код не надсилається в браузер import { db } from '@/lib/db' export default async function UserStats() { const totalUsers = await db.user.count() const totalProblems = await db.problem.count() return ( <div> <p>Користувачі на IT Lead: {totalUsers}</p> <p>Проблеми: {totalProblems}</p> </div> ) }

Коли вам потрібна інтерактивність, позначте компонент як клієнтський компонент:

tsx
'use client' import { useState } from 'react' export default function ThemeToggle() { const [dark, setDark] = useState(false) return ( <button onClick={() => setDark(!dark)}> {dark ? 'Світлий режим' : 'Темний режим'} </button> ) }

Важливо:

Серверні компоненти не можуть використовувати useState, useEffect, onClick та інші клієнтські API. Якщо вам потрібна інтерактивність, виділіть її в окремий клієнтський компонент.

Серверні дії

Серверні дії дозволяють вам викликати серверні функції безпосередньо з компонентів без створення API-інтерфейсів:

tsx
// actions/subscribe.ts 'use server' import { db } from '@/lib/db' export async function subscribe(email: string) { await db.subscriber.create({ data: { email } }) }
tsx
// Клієнтський компонент викликає серверну функцію 'use client' import { subscribe } from '@/actions/subscribe' export default function SubscribeForm() { return ( <form action={async (formData) => { const email = formData.get('email') as string await subscribe(email) }}> <input name="email" type="email" placeholder="Email" /> <button type="submit">Підписатися на IT Lead</button> </form> ) }

Вкладені макети

Макети в Next.js зберігають стан між навігаціями. Якщо у вас є бокова панель або навігація, вони не перерисовуються при переході між сторінками:

tsx
// app/docs/layout.tsx // Цей макет обгортає всі /docs/* сторінки export default function DocsLayout({ children }: { children: React.ReactNode }) { return ( <div className="flex"> <Sidebar /> <main className="flex-1">{children}</main> </div> ) }

При переході з /docs/javascript на /docs/react макет з боковою панеллю залишається на місці. Лише вміст children перерисовується.

Вбудована оптимізація

Компонент зображення

Автоматично оптимізує зображення: змінює розмір, конвертує в WebP/AVIF, додає лінійне завантаження:

tsx
import Image from 'next/image' export default function Avatar() { return ( <Image src="/avatar.png" width={64} height={64} alt="Аватар користувача" /> ) }

Компонент посилання

Попередньо завантажує сторінку у фоновому режимі, коли посилання входить у видимість. Навігація стає майже миттєвою:

tsx
import Link from 'next/link' export default function Nav() { return ( <nav> <Link href="/problems">Проблеми</Link> <Link href="/docs">Документація</Link> </nav> ) }

Оптимізація шрифтів

next/font завантажує шрифти без зсуву макета та без запитів на стороні клієнта до Google Fonts:

tsx
import { Inter } from 'next/font/google' const inter = Inter({ subsets: ['latin', 'cyrillic'] }) export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html className={inter.className}> <body>{children}</body> </html> ) }

Проміжне ПЗ

Проміжне ПЗ виконується перед обробкою запиту і дозволяє вам перенаправляти, переписувати URL або змінювати заголовки:

tsx
// middleware.ts (в корені проекту) import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { const locale = request.cookies.get('locale')?.value || 'en' if (!request.nextUrl.pathname.startsWith(`/${locale}`)) { return NextResponse.redirect( new URL(`/${locale}${request.nextUrl.pathname}`, request.url) ) } } export const config = { matcher: ['/((?!api|_next|favicon).*)'] }

Вбудована підтримка метаданих

Next.js надає зручний API для управління SEO-метаданими:

tsx
import type { Metadata } from 'next' export const metadata: Metadata = { title: 'JavaScript Problems — IT Lead', description: 'Розв'язуйте проблеми з реальних фронтенд-інтерв'ю', openGraph: { title: 'JavaScript Problems', description: 'Розв'язуйте проблеми з реальних фронтенд-інтерв'ю', type: 'website' } } export default function ProblemsPage() { return <ProblemsList /> }

Повна картина

Запит

Проміжне ПЗ

App Router

Макет

Серверний компонент

Клієнтський компонент

База даних

Зовнішній API

Серверна дія Як відповісти на інтерв'ю:

Не перераховуйте всі функції. Виберіть 3-4 ключові та поясніть, як вони пов'язані. Наприклад: "Next.js використовує App Router з маршрутизацією на основі файлів, де компоненти за замовчуванням є серверними компонентами, що зменшує пакет для клієнта та надає прямий доступ до даних без API-шару через серверні дії".

Корисні ресурси

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань