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

Монолитный бандл замедляет загрузку сайта, отпугивая пользователей и снижая конверсию. Мы реализуем lazy loading компонентов, чтобы сократить стартовый код и ускорить отклик интерфейса. Наша команда внедряет отложенную загрузку под ключ — от аудита до поддержки, обеспечивая стабильную работу и рост метрик Core Web Vitals.

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

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

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

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

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

Типичная ситуация: 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.

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

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

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1140
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060