Сравни способы применения React.Suspense и объясни, когда выбирать каждый вариант.
Рендеринг и производительность
Suspense показывает fallback, пока поддерево не готово. Применяется в нескольких режимах — выбирать по источнику «неготовности».
Ленивая загрузка кода (React.lazy)
const Editor = lazy(() => import('./Editor'));
<Suspense fallback={<Skeleton />}><Editor /></Suspense>Выбирать: code splitting по маршрутам и тяжёлым виджетам — уменьшить первый бандл. Самый распространённый и безопасный случай.
Ожидание данных
С библиотеками (useSuspenseQuery в TanStack Query) или хуком use(promise) в React 19: компонент пишется так, будто данные есть, состояния загрузки — на границе Suspense.
Выбирать: когда хочется убрать if (isLoading) из компонентов и централизовать скелетоны. Требует поддержки на уровне библиотеки/фреймворка.
Серверные компоненты и стриминговый SSR
<Suspense fallback={<CommentsSkeleton />}>
<Comments /> {/* медленный серверный компонент придёт позже */}
</Suspense>Выбирать: Next.js App Router — быстрая отдача каркаса страницы, медленные блоки стримятся отдельно и не блокируют показ.
Плавные переходы
С useTransition/useDeferredValue уже отрисованный контент не заменяется fallback'ом при обновлении — вместо «мигания скелетоном» показывается старое состояние с индикатором.
Выбирать: навигация и фильтры, где мигание раздражает.
Правила расстановки границ
По смысловым блокам (страница, крупный виджет), а не вокруг каждого компонента; парой с Error Boundary (Suspense ошибки не ловит); fallback — скелетон нужной геометрии, чтобы не прыгал layout.
Коротко для собеседования
Режимы: React.lazy (code splitting — основной кейс), ожидание данных (useSuspenseQuery/use — убирает isLoading из компонентов), стриминговый SSR с серверными компонентами (быстрый каркас), плавные переходы с useTransition (без мигания fallback). Границы — по блокам, всегда в паре с Error Boundary.