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

В чем особенность React SSR?

2.0 Middle🔥 241 комментариев
#React#Оптимизация и производительность

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

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

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

React Server-Side Rendering (SSR): особенности и подводные камни

React SSR — это рендеринг React компонентов на сервере (Node.js) с отправкой готового HTML клиенту. На первый взгляд это звучит просто, но SSR кардинально меняет архитектуру приложения и привносит множество сложностей.

Основная концепция SSR

// ТРАДИЦИОННЫЙ CSR (Client-Side Rendering)
// 1. Браузер получает пустой <div id="root"></div>
// 2. Загружает main.js (большой бандл)
// 3. JavaScript гидрирует DOM
// 4. Страница становится интерактивной
// Время до интерактивности: 3-5 сек

// SSR (Server-Side Rendering)
// 1. Сервер выполняет React код
// 2. Генерирует готовый HTML
// 3. Отправляет браузеру
// 4. Браузер отображает (быстро!)
// 5. JavaScript гидрирует страницу
// Время до интерактивности: 1-2 сек

Главные особенности React SSR

1. Гидратация (Hydration)

Гидратация — это когда JavaScript на клиенте "оживляет" уже отрисованный HTML:

// На сервере
import { renderToString } from 'react-dom/server';

const App = () => <h1>Hello {name}</h1>;
const html = renderToString(<App />);
// Результат: "<h1>Hello World</h1>"
// Отправляем браузеру

// На браузере
import { hydrateRoot } from 'react-dom/client';

const root = hydrateRoot(
  document.getElementById('root'),
  <App />
);
// React НЕ пересчитывает, а просто подключает обработчики событий

Важная особенность: React должен отрендерить ТУ ЖЕ структуру на клиенте, иначе будет ошибка "Hydration mismatch":

// ❌ ОШИБКА: Браузер выполняет другой код
const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
      // На сервере: count = 0 (начальное значение)
      // На клиенте: count = 5 (случайное)
      Count: {count}
    </div>
  );
};

// ✅ ПРАВИЛЬНО: Используй useEffect для клиент-only кода
const App = () => {
  const [count, setCount] = useState(0);
  const [isClient, setIsClient] = useState(false);
  
  useEffect(() => {
    setIsClient(true);
    setCount(5); // Обновление после гидратации
  }, []);
  
  if (!isClient) return null; // На сервере пропускаем
  return <div>Count: {count}</div>;
};

2. Отсутствие Browser API на сервере

На Node.js сервере нет window, document, localStorage, sessionStorage и других browser API:

// ❌ ОШИБКА: ReferenceError: window is not defined
const MyComponent = () => {
  const theme = localStorage.getItem('theme'); // CRASH на сервере
  return <div>{theme}</div>;
};

// ✅ ПРАВИЛЬНО: Проверяй наличие window
const MyComponent = () => {
  const [theme, setTheme] = useState('light');
  
  useEffect(() => {
    if (typeof window !== 'undefined') {
      const savedTheme = localStorage.getItem('theme');
      setTheme(savedTheme || 'light');
    }
  }, []);
  
  return <div>{theme}</div>;
};

// Или используй условное импортирование
const getTheme = () => {
  if (typeof window !== 'undefined') {
    return localStorage.getItem('theme');
  }
  return 'light'; // Дефолт на сервере
};

3. Streaming SSR (React 18+)

Вместо ожидания полной отрисовки, React может отправлять HTML по частям (streaming):

// Старый подход (SSR blocking)
import { renderToString } from 'react-dom/server';

const html = renderToString(<App />); // Ждём всё
response.send(html);

// Новый подход (Streaming)
import { renderToPipeableStream } from 'react-dom/server';

const { pipe } = renderToPipeableStream(<App />, {
  onShellReady() {
    response.setHeader('content-type', 'text/html');
    pipe(response);
  },
  onError(error) {
    console.error(error);
  }
});

Преимущество: Браузер получает HTML максимально быстро, может рендерить во время загрузки данных

4. Data Fetching на сервере

Од из главных преимуществ SSR — можно загружать данные на сервере ПЕРЕД отправкой HTML:

// Server Component (Next.js 13+)
export const getServerSideProps = async () => {
  const posts = await fetch('https://api.example.com/posts');
  return {
    props: { posts }
  };
};

export default function Blog({ posts }) {
  // posts уже здесь, не нужен useEffect для загрузки
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

Когда браузер получает HTML, данные уже внутри. Это избегает waterfalls (жду загрузку JS -> жду загрузку данных).

5. Проблемы с SSR

a) Стек размножается:

// На сервере нужна одна версия React
// На клиенте нужна другая версия React
// Могут быть конфликты версий

b) Производительность сервера:

// Каждый запрос требует рендеринга React
// На тысячах пользователей это дорого
// Решение: кэширование, ISR (Incremental Static Regeneration)

c) Сложность разработки:

// Код должен работать и на сервере, и на клиенте
// Больше способов что-то сломать
// Больше edge cases

Сравнение подходов

CSR (Client-Side Rendering):

  • Плюсы: Просто, быстрая разработка, масштабируемо на миллионы пользователей
  • Минусы: Медленное время загрузки, нет SEO, большие JS бандлы

SSR (Server-Side Rendering):

  • Плюсы: Быстрое время загрузки (FCP), хороший SEO, улучшенный UX
  • Минусы: Сложная разработка, дорогой сервер, требует Node.js

SSG (Static Site Generation):

  • Плюсы: Максимальная производительность, бесплатный хостинг (CDN), хороший SEO
  • Минусы: Не подходит для динамичного контента

ISR (Incremental Static Regeneration) - Next.js:

  • Плюсы: Комбинирует SSG и SSR — лучшее из обоих миров
  • Минусы: Специфично для Next.js

Практический пример Next.js (SSR + ISR)

// next.config.js
module.exports = {
  // SSR для динамического контента
  getServerSideProps: async (context) => {
    const post = await db.posts.findById(context.params.id);
    return {
      props: { post },
      revalidate: 60 // ISR: переgenerate каждые 60 сек
    };
  }
};

// pages/posts/[id].js
export default function Post({ post }) {
  return <h1>{post.title}</h1>;
}

Вывод

React SSR особенно полезен:

  1. SEO-зависимые сайты (блоги, новостные сайты)
  2. Медленные мобильные сети (быстрое FCP)
  3. Dynamic контент (курсы, профили пользователей)
  4. Улучшенный UX (контент видишь раньше, чем интерактивен)

Но добавляет сложность:

  • Hydration mismatch ошибки
  • Нет Browser API на сервере
  • Больше производительности сервера
  • Сложнее отлаживать

Мой совет: Используй SSR через Next.js с ISR — это даёт лучший баланс производительности и разработки. Чистый SSR часто избыточен для большинства проектов.

В чем особенность React SSR? | PrepBro