Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як розділити код React-застосунку через lazy і Suspense?

За замовчуванням збирач кладе весь код застосунку в один файл: користувач, що відкрив головну сторінку, завантажує й код адмінки, редактора, графіків. Розділення коду (code splitting) виносить частини в окремі файли, що завантажуються за потреби.

lazy - компонент, код якого завантажується при першому рендері:

import { lazy, Suspense } from 'react';

const MarkdownEditor = lazy(() => import('./MarkdownEditor'));

function PostForm() {
  const [editing, setEditing] = useState(false);
  return (
    <>
      <button onClick={() => setEditing(true)}>Редагувати</button>
      {editing && (
        <Suspense fallback={<p>Завантаження редактора...</p>}>
          <MarkdownEditor />
        </Suspense>
      )}
    </>
  );
}

Збирач (Vite) бачить динамічний import() і виносить MarkdownEditor з усіма залежностями в окремий файл.

Suspense показує fallback, поки код завантажується. Одна межа Suspense може охоплювати кілька лінивих компонентів.

Правила:

  • lazy - на верхньому рівні модуля, не всередині компонента. Інакше на кожен рендер створюється новий компонент - стан губиться, і код завантажується знову;
  • модуль має експортувати компонент за замовчуванням (export default). Для іменованого експорту - проміжний модуль чи import('./x').then((m) => ({ default: m.Editor }));
  • помилка завантаження (мережа, файл зник після деплою) кидається як виняток - потрібна межа помилок (Error Boundary), щоб показати повідомлення й кнопку «Оновити».

Що варто виносити:

  • сторінки й маршрути - найприродніша межа; маршрутизатори (React Router, TanStack Router) мають для цього вбудовану підтримку;
  • важкі бібліотеки - редактори, графіки, карти, PDF;
  • рідко потрібне - модальні вікна налаштувань, експорт.

Не варто дробити кожен компонент: багато дрібних файлів - багато запитів і затримки «водоспадом». Межі - за сценаріями використання.

Попереднє завантаження: щоб користувач не чекав після кліку, імпорт можна запустити заздалегідь - при наведенні на кнопку: onMouseEnter={() => import('./MarkdownEditor')}. Повторний import() використає вже завантажений модуль.

Inertia розділяє код за сторінками автоматично, якщо в resolve використовується import.meta.glob без eager: true.

Докладніше в документації: lazy

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання