← Назад к вопросам

Как работает метод ToString?

2.0 Middle🔥 161 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизм генерации HTML в Next.js

Next.js использует несколько стратегий рендеринга для преобразования React компонентов в HTML. Понимание этих механизмов критично для оптимизации производительности и SEO.

SSR (Server-Side Rendering)

// app/page.tsx - по умолчанию SSR в Next.js 13+
import { db } from '@/lib/db';

export default async function HomePage() {
  // Это асинхронный компонент - выполняется на сервере
  const posts = await db.posts.findMany();

  // HTML генерируется на сервере с реальными данными
  return (
    <main>
      <h1>Посты</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </main>
  );
}

// Процесс:
// 1. Запрос пришел на /
// 2. Next.js запустил HomePage компонент на сервере
// 3. Выполнил await db.posts.findMany()
// 4. React превратил JSX в HTML строку
// 5. Отправил HTML клиенту
// 6. Браузер отображает HTML
// 7. React hydrate интерактивности (если нужны)

SSG (Static Site Generation)

// app/posts/[slug]/page.tsx
export async function generateStaticParams() {
  // Эта функция выполняется на билд-тайме
  const posts = await db.posts.findMany();
  
  // Возвращает все возможные параметры
  return posts.map(post => ({
    slug: post.slug
  }));
}

export default async function PostPage({ params }) {
  const post = await db.posts.findUnique({
    where: { slug: params.slug }
  });

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  );
}

// Процесс на bildjoin time (npm run build):
// 1. Next.js вызывает generateStaticParams()
// 2. Получает список всех постов: [{slug: 'post-1'}, {slug: 'post-2'}...]
// 3. Для каждого slug генерирует папку: posts/post-1/page.html, posts/post-2/page.html
// 4. Сохраняет статический HTML
// 5. При запросе просто отдает готовый HTML

ISR (Incremental Static Regeneration)

// app/articles/[id]/page.tsx
export const revalidate = 60; // переиндексировать каждые 60 сек

export async function generateStaticParams() {
  return [
    { id: '1' },
    { id: '2' },
    { id: '3' }
  ];
}

export default async function ArticlePage({ params }) {
  const article = await db.articles.findUnique({
    where: { id: params.id }
  });

  return (
    <article>
      <h1>{article.title}</h1>
      <time>{article.updatedAt}</time>
    </article>
  );
}

// Процесс ISR:
// 1. Генерируются статические страницы при билде
// 2. При первом запросе после 60 сек отдается старая версия
// 3. В фоне на сервере регенерируется новая версия
// 4. Следующий запрос получит новую версию
// 5. Если вывести новый ID, Next.js создаст новую страницу on-demand

CSR (Client-Side Rendering)

// 'use client' - этот файл исполняется в браузере
'use client';

import { useState, useEffect } from 'react';

export default function InteractiveComponent() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Этот код выполняется только в браузере
    fetch('/api/v1/data')
      .then(r => r.json())
      .then(setData)
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <div>Загрузка...</div>;

  return <div>{data.message}</div>;
}

// Процесс CSR:
// 1. Сервер отправляет HTML скелет (обычно с Suspense fallback)
// 2. Браузер загружает JavaScript бандл
// 3. React hydrate компонент
// 4. useEffect запускает fetch запрос
// 5. После получения данных компонент обновляется

Гибридный подход

// app/dashboard/page.tsx
import { Suspense } from 'react';
import StaticHeader from '@/components/StaticHeader'; // SSR
import UserPanel from '@/components/UserPanel'; // SSR
import RealtimeChart from '@/components/RealtimeChart'; // CSR

export default function Dashboard() {
  return (
    <main>
      <StaticHeader /> {/* Отрендерится на сервере */}
      
      <Suspense fallback={<div>Загрузка панели...</div>}>
        <UserPanel /> {/* Может быть асинхронным */}
      </Suspense>
      
      <RealtimeChart /> {/* Клиентский компонент с real-time updates */}
    </main>
  );
}

// Процесс:
// 1. StaticHeader и UserPanel рендерятся на сервере
// 2. RealtimeChart отправляется как JS код
// 3. Браузер получает готовый HTML + hydrate реактивные части

Процесс на билд-тайме

build/
├── server/         # Серверный код для SSR
├── static/         # Статические страницы (SSG)
├── .next/
│   ├── cache/      # Кэш для ISR
│   └── routes-manifest.json

Процесс:
1. Парс app/ директории
2. Определение типа каждой страницы (SSR/SSG/ISR)
3. Вызов generateStaticParams() для SSG
4. Генерация HTML для статических страниц
5. Подготовка серверного кода для SSR
6. Создание бандла клиентского JavaScript
7. Создание manifest файлов для маршрутизации

Оптимизация

// Кэширование запросов
export default async function Page() {
  // Автоматически кэшируется
  const data = await fetch('/api/v1/data', { 
    next: { revalidate: 3600 } // кэш на 1 час
  });

  return <div>{data}</div>;
}

// Использование ISR для часто меняющихся данных
export const revalidate = 10; // обновлять каждые 10 сек

// Ленивая загрузка для тяжелых компонентов
const HeavyComponent = dynamic(() => import('@/components/Heavy'), {
  ssr: false,           // не генерировать на сервере
  loading: () => <div>Загрузка...</div>
});

Выбор стратегии зависит от типа данных: статические данные -> SSG, динамические -> SSR, реал-тайм -> CSR.

Как работает метод ToString? | PrepBro