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

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

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

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

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация Lazy Loading компонентов на сайте
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы

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

Этапы разработки

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

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

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

Lazy loading — отложенная загрузка компонентов, изображений или модулей до момента, когда они реально нужны пользователю. Уменьшает размер начального бандла, ускоряет Time to Interactive и снижает расход трафика на мобильных устройствах.

Два уровня lazy loading

Уровень модулей — JavaScript-код компонента загружается только при первом рендере. Реализуется через динамический import().

Уровень ресурсов — изображения, iframe, видео загружаются только когда элемент входит в область видимости. Реализуется через атрибут loading="lazy" или IntersectionObserver.

React.lazy и Suspense

// Без lazy loading — весь код попадает в main bundle
import HeavyChart from '@/components/HeavyChart'
import DataTable from '@/components/DataTable'

// С lazy loading — отдельные чанки, загружаются по требованию
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. Как только чанк загружен — рендерит компонент.

Именованные экспорты с lazy

React.lazy работает только с default export. Для именованных нужна обёртка:

// Если компонент экспортируется как named export
const BarChart = lazy(() =>
  import('@/components/charts').then(module => ({
    default: module.BarChart,
  }))
)

Условная загрузка: только при видимости

Загружать тяжёлый компонент сразу при монтировании страницы — не всегда нужно. Если компонент находится внизу страницы, стоит отложить загрузку до прокрутки к нему:

// 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 изображений

// Нативный lazy loading — поддерживается всеми современными браузерами
function ProductCard({ product }: { product: Product }) {
  return (
    <div>
      <img
        src={product.image}
        alt={product.title}
        loading="lazy"
        decoding="async"
        width={400}
        height={300}
      />
    </div>
  )
}

Для более тонкого контроля — кастомный хук с IntersectionObserver:

function useLazyImage(src: string) {
  const imgRef = useRef<HTMLImageElement>(null)
  const [loaded, setLoaded] = useState(false)

  useEffect(() => {
    const img = imgRef.current
    if (!img) return

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          img.src = src
          img.onload = () => setLoaded(true)
          observer.disconnect()
        }
      },
      { rootMargin: '100px' }
    )

    observer.observe(img)
    return () => observer.disconnect()
  }, [src])

  return { imgRef, loaded }
}

Next.js: dynamic import

import dynamic from 'next/dynamic'

// С кастомным loading state
const RichTextEditor = dynamic(
  () => import('@/components/RichTextEditor'),
  {
    loading: () => <EditorSkeleton />,
    ssr: false, // не рендерить на сервере — актуально для window-dependent компонентов
  }
)

// Только при выполнении условия
const AdminPanel = dynamic(() => import('@/components/AdminPanel'), { ssr: false })

function Page({ isAdmin }: { isAdmin: boolean }) {
  return isAdmin ? <AdminPanel /> : <UserView />
}

Vite: анализ бандла

Чтобы понять, что стоит выносить в lazy chunks:

# Установить плагин
npm install --save-dev rollup-plugin-visualizer

# vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'

export default {
  plugins: [
    visualizer({ open: true, gzipSize: true, filename: 'dist/stats.html' }),
  ],
}

После npm run build откроется интерактивная карта бандла. Ищем крупные зависимости: chart libraries, rich text editors, date pickers, map SDKs — первые кандидаты на lazy loading.

Preload критичных чанков

Чанки, которые почти гарантированно понадобятся, можно prefetch в idle time:

// Prefetch при hover на ссылку
function NavLink({ href, chunkImport, children }) {
  const handleMouseEnter = () => {
    chunkImport() // () => import('@/pages/About')
  }
  return <a href={href} onMouseEnter={handleMouseEnter}>{children}</a>
}

Сроки

Настройка React.lazy + Suspense для существующих компонентов — 0.5 дня. Полный аудит бандла, приоритизация, реализация intersection-based загрузки с skeleton-заглушками — 2–3 дня в зависимости от количества компонентов.