JavaRush /Курсы /Модуль 3: React /Создание динамических загрузок с помощью React.lazy и Sus...

Создание динамических загрузок с помощью React.lazy и Suspense

Модуль 3: React
10 уровень , 3 лекция
Открыта

Зачем использовать динамическую загрузку?

Итак, представьте, что ваше приложение — это чемодан, и вы идёте через аэропорт. Чем больше вещей в чемодане, тем тяжелее его нести. То же самое и с приложением: чем больше кода грузится сразу, тем дольше пользователи ждут, пока оно загрузится. Здесь на помощь приходит React.lazy, который позволяет загружать "части кода" — компоненты, — только тогда, когда они нужны.

Преимущества динамической загрузки:

  • Уменьшение начального времени загрузки. Рендерить только то, что нужно, и когда это нужно.
  • Оптимизация производительности. Деление приложения на "части" (chunk'и) помогает браузеру быстрее справляться с загрузкой.
  • Лучшая пользовательская вовлеченность. Быстрее загружается первая видимая часть приложения (First Contentful Paint), а остальные — подгружаются по мере необходимости.

Введение в React.lazy и Suspense

React.lazy — это встроенный в React механизм для ленивой загрузки компонентов. Вместе с ним используется Suspense, который позволяет показывать пользователям, например, индикатор загрузки, пока компонент ещё не загрузился.

Код выглядит примерно так:

import React, { Suspense } from 'react';

// "Ленивая" загрузка компонента
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Загрузка...</div>}>
      <LazyComponent />
    </Suspense>
);
}

Как это работает?

  • React.lazy(() => import('./LazyComponent')): мы используем динамический импорт, чтобы загрузить компонент только когда он нужен. React.lazy автоматически оборачивает его в промис и загружает в нужный момент.
  • Suspense: это обертка, которая позволяет показывать запасной контент, пока ленивая загрузка завершится. В нашем случае это <div>Загрузка...</div>.

Пример реализации ленивой загрузки

Теперь давайте возьмем реальный пример. Представьте, что у нас есть приложение с несколькими крупными страницами: главная, страница профиля и страница настроек. Нам нужно сделать так, чтобы каждая страница загружалась только тогда, когда пользователь на неё переходит.

Шаг 1. Создаем компоненты

Создадим три файла в директории src/pages/:

// Home.tsx
const Home = () => <h1>Добро пожаловать на главную страницу!</h1>;
export default Home;

// Profile.tsx
const Profile = () => <h1>Это страница профиля</h1>;
export default Profile;

// Settings.tsx
const Settings = () => <h1>Настройки вашего аккаунта</h1>;
export default Settings;

Шаг 2. Используем React.lazy и Suspense

Теперь изменим наш App.tsx, чтобы страницы загружались динамически:

import React, { Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

// Ленивая загрузка страниц
const Home = React.lazy(() => import('./pages/Home'));
const Profile = React.lazy(() => import('./pages/Profile'));
const Settings = React.lazy(() => import('./pages/Settings'));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Загрузка страницы...</div>}>
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/profile" component={Profile} />
          <Route path="/settings" component={Settings} />
        </Switch>
      </Suspense>
    </Router>
  );
}

export default App;

Шаг 3. Добавляем навигацию

Добавим ссылки для перехода между страницами:

import React from 'react';
import { Link } from 'react-router-dom';

const Navigation = () => (
  <nav>
    <ul>
      <li><Link to="/">Главная</Link></li>
      <li><Link to="/profile">Профиль</Link></li>
      <li><Link to="/settings">Настройки</Link></li>
    </ul>
  </nav>
);

export default Navigation;

И используем компонент Navigation в App:

function App() {
  return (
    <Router>
      <Navigation />
      <Suspense fallback={<div>Загрузка страницы...</div>}>
        {/* остальные части */}
      </Suspense>
    </Router>
  );
}

Улучшение пользовательского опыта с Suspense и кастомными фолбэками

Простой fallback={<div>Загрузка...</div>} — это, конечно, мило, но пользователи достойны большего. Давайте сделаем более привлекательный индикатор загрузки.

Пример кастомного индикатора

Создадим компонент Spinner.tsx:

import React from 'react';

const Spinner = () => (
  <div className="spinner">
    <div className="spinner__circle"></div>
    <p>Пожалуйста, подождите...</p>
  </div>
);

export default Spinner;

Добавим стили в App.css:

.spinner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.spinner__circle {
  width: 50px;
  height: 50px;
  border: 5px solid lightgray;
  border-top-color: blue;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

Теперь используем Spinner вместо fallback:

<Suspense fallback={<Spinner />}>
  {/* лениво загружаемые компоненты */}
</Suspense>

Пользователь увидит эффектный индикатор загрузки, пока компонент загружается.

Типизация компонентов для React.lazy

Чтобы загрузка компонентов оставалась безопасной с точки зрения типов, мы можем использовать интерфейсы TypeScript.

Пример типизации загружаемого компонента

Допустим, наш компонент Profile принимает пропсы:

interface ProfileProps {
  userId: string;
}

const Profile: React.FC<ProfileProps> = ({ userId }) => (
  <h1>Профиль пользователя с ID: {userId}</h1>
);

export default Profile;

В этом случае типизацию можно применить следующим образом:

const Profile = React.lazy(() => import('./pages/Profile') as Promise<React.ComponentType<ProfileProps>>);

Так мы обеспечиваем строгую типизацию при использовании ленивой загрузки.

Типичные ошибки и их решение

Ошибка 1: React.lazy не работает без Suspense.
React.lazy обязательно требует обертки в Suspense. Если забыть Suspense, получите ошибку. Поэтому не забудьте всегда оборачивать лениво загружаемые компоненты в <Suspense>.

Ошибка 2: Фолбэк не должен быть "тяжёлым".
Фолбэк (fallback) — это временное отображение, пока компонент загружается. Если вы используете слишком ресурсоёмкий элемент (например, сложные анимации), это может снова замедлить приложение.

Ошибка 3: Неправильные пути в импортах.
Если путь к компоненту в import() некорректен, браузер просто не сможет загрузить его. Подключите TypeScript, чтобы избежать таких ошибок.

Применение в реальных проектах

Ленивую загрузку часто используют в реальных приложениях для:

  • Подключения страниц в крупном приложении.
  • Загрузки редко используемых виджетов (например, "чаты", "аналитические графики").
  • Разделения кода на модули, чтобы улучшить производительность.

Такой подход часто проверяется на собеседованиях, особенно если речь идёт о производительности. Поэтому знать React.lazy и Suspense не просто полезно — это важно!

1
Задача
Модуль 3: React, 10 уровень, 3 лекция
Недоступна
Создание ленивого компонента
Создание ленивого компонента
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ