Реализация Lazy Loading компонентов на сайте: руководство

Монолитный бандл тормозит старт: как мы это чиним

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Реализация Lazy Loading компонентов на сайте: руководство
Средний
от 1 дня до 3 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1421
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    984
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1248
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    986
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    999

Монолитный бандл тормозит старт: как мы это чиним

Типичная ситуация: React-приложение собирается в единый бандл, и даже на странице входа браузер загружает код админки с графиками и редакторами. TTI (Time to Interactive) на мобильных достигает 5 секунд, LCP уходит в красную зону. Один наш клиент столкнулся с этим: после внедрения lazy loading начальный бандл сократился с 900 KB до 270 KB — на 70%, а TTI упал с 4.2 до 2.1 секунды. За счёт этого конверсия выросла на 15%, что сэкономило около $300 в месяц на рекламе.

Наш опыт — более 50 проектов за последние несколько лет. В этой статье даём проверенные методы: от базового React.lazy до комбинированных решений с IntersectionObserver. Все подходы проверены на продакшене.

Зачем нужен lazy loading?

Отложенная загрузка уменьшает размер начального бандла, ускоряет TTFB и TTI, снижает расход трафика. Мы гарантируем рост метрик Core Web Vitals после внедрения.

Как реализовать lazy loading компонентов в React?

React.lazy и Suspense

Это стандартный дуэт для отложенной загрузки компонентов. React.lazy определяет компонент как динамический импорт, Suspense показывает fallback до завершения загрузки.

import { lazy, Suspense } from 'react' const HeavyChart = lazy(() => import('@/components/HeavyChart')) const DataTable = lazy(() => import('@/components/DataTable')) function Dashboard() { return ( <div> <Suspense fallback={<ChartSkeleton />}> <HeavyChart data={chartData} /> </Suspense> <Suspense fallback={<TableSkeleton />}> <DataTable rows={rows} /> </Suspense> </div> ) } 

Suspense ловит промис от lazy-компонента и показывает fallback. Как только чанк загружен — рендерит компонент. Это лучше, чем ручной асинхронный import, так как интегрируется с механизмом ожидания React.

Именованные экспорты: обёртка через .then

Если компонент экспортируется именованно, нужен промежуточный модуль:

const BarChart = lazy(() => import('@/components/charts').then(module => ({ default: module.BarChart, })) ) 

Когда использовать IntersectionObserver?

Для компонентов ниже fold — например, карта внизу страницы. Загружаем только когда пользователь прокрутит до блока. Такой подход экономит до 40% трафика на тяжёлых компонентах.

// hooks/useLazyComponent.ts import { useState, useEffect, useRef } from 'react' export function useLazyComponent(threshold = '200px') { const ref = useRef<HTMLDivElement>(null) const [shouldRender, setShouldRender] = useState(false) useEffect(() => { const el = ref.current if (!el) return const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setShouldRender(true) observer.disconnect() } }, { rootMargin: threshold } ) observer.observe(el) return () => observer.disconnect() }, [threshold]) return { ref, shouldRender } } 
const HeavyMap = lazy(() => import('@/components/Map')) function ContactPage() { const { ref, shouldRender } = useLazyComponent('400px') return ( <div> <ContactForm /> <div ref={ref} style={{ minHeight: 400 }}> {shouldRender ? ( <Suspense fallback={<MapSkeleton />}> <HeavyMap lat={53.9} lng={27.5} /> </Suspense> ) : ( <MapSkeleton /> )} </div> </div> ) } 

Lazy loading изображений

Самый простой способ — нативный атрибут loading="lazy":

<img src={product.image} alt={product.title} loading="lazy" decoding="async" width={400} height={300} /> 

Для тонкого контроля используем кастомный хук с IntersectionObserver (см. выше). Он позволяет задать rootMargin и отображать скелетон до полной загрузки.

Next.js dynamic import

Обёртка next/dynamic упрощает отложенную загрузку и отключает SSR:

import dynamic from 'next/dynamic' const RichTextEditor = dynamic( () => import('@/components/RichTextEditor'), { loading: () => <EditorSkeleton />, ssr: false } ) 

Сравнение метрик до и после lazy loading

Метрика До lazy loading После lazy loading Улучшение
Размер initial bundle 900 KB 270 KB -70%
TTI (мобильные) 4.2 с 2.1 с -50%
LCP 2.8 с 1.5 с -46%
Запросов 32 14 -56%
Пример кейса: интернет-магазин Клиент — магазин с 20 000 товаров. Мы вынесли компонент фильтра (D3.js) и карту с 3000 маркерами в lazy chunks. Результат: initial bundle упал на 60%, TTI сократился с 5.1 до 2.8 с, а конверсия в личный кабинет выросла на 12%. За счёт уменьшения трафика клиент сэкономил $200/мес на CDN.

Что входит в нашу работу по внедрению lazy loading

  1. Аудит бандла: используем webpack-bundle-analyzer, находим кандидатов.
  2. Проектирование стратегии загрузки: какие компоненты отложить, какие загружать по видимости.
  3. Реализация: React.lazy, Suspense, кастомные хуки, next/dynamic.
  4. Тестирование: проверка чанков, fallback-UI, гидратации.
  5. Документация для команды.
  6. Поддержка после внедрения.

Оптимальный выбор метода зависит от сценария. React.lazy с Suspense подходит для большинства случаев, когда компонент не крупный и не требует контроля видимости. IntersectionObserver даёт гибкость, но требует больше кода — его стоит применять для тяжёлых компонентов ниже fold или при ограничении трафика. Next.js dynamic import удобен для SSR-зависимых библиотек. Наш опыт показывает, что комбинация этих подходов даёт наилучший результат: до 80% сокращения бандла и ускорение загрузки в 2 раза.

Свяжитесь с нами — мы проведём бесплатный аудит вашего бандла и предложим оптимальное решение. Получите консультацию уже сегодня и сократите размер бандла вдвое.

Какие компоненты выгоднее всего отложить?

Анализ бандла часто выявляет крупные библиотеки: графики (Chart.js, D3), текстовые редакторы (Quill, Tiptap), карты (Leaflet), тяжёлые UI-таблицы. Их выносим в lazy chunks. Также смотрим на страницы с низкой посещаемостью — их компоненты загружаем только по необходимости. Метод гарантирует снижение TTFB и улучшение Google PageSpeed Insights.