Детерминированный Suspense в React 19: Zero-CLS через типизированный fallback при SSR
Детерминированный Suspense в React 19: Zero-CLS через типизированный fallback при SSR Layout shift при SSR с Suspense — хроническая боль для CLS и LCP. Классический подход рендерит fallback только на клиенте, вызывая дёрганье UI во время гидрации. React 19 исправляет это через пропс clientOnlyFallback={false}, позволяя серверу вставлять типизированный fallback с фиксированной высотой. Почему это важно При SSR без детерминированного fallback браузер не резервирует место под асинхронный контент. В момент гидрации контент появляется, и CLS улетает в красную зону. Решение — серверный fallback с явно заданными размерами, который не меняется при гидрации. Типизированный fallback с предсказуемой высотой Используйте интерфейс с обязательными height (в пикселях) и placeholder, чтобы браузер зарезервировал место до загрузки данных: interface FallbackProps { height: number; placeholder: string; } function StaticFallback({ height, placeholder }: FallbackProps) { return ( <div style={{ height: ${height}px, opacity: 0.3, background: '#f0f0f0', pointerEvents: 'none' }} aria-hidden="true" > {placeholder} </div> ); } function AsyncComponent() { return ( <Suspense fallback={<StaticFallback height={200} placeholder="Загрузка..." />} clientOnlyFallback={false} > <ActualData /> </Suspense> ); } Типичная ошибка Пропуск height или передача нерелевантной высоты. Если размер fallback'а не совпадёт с реальным контентом, CLS вернётся. Для динамических блоков без фиксированной высоты используйте aspect-ratio CSS-свойство в style или вычисляйте размер через IntersectionObserver на сервере. Production-совет Для карточек, списков и таблиц — резервируйте высоту с запасом 10% от ожидаемой. Для блоков с неизвестным контентом комбинируйте min-height и max-height, чтобы избежать пустоты или наложения. Тестируйте на реальных метриках Lighthouse. Вывод: Типизированный fallback с clientOnlyFallback={false} — минимальный шаг к нулевому CLS в SSR, но требует точного знания размеров контента, иначе trade-off между стабильностью и производительностью.