Как использовать React Suspense с ленивой загрузкой?react-54

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

1. Базовый пример

import { lazy, Suspense } from 'react';

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

function App() {
  return (
    <Suspense fallback={<div>Загружаем компонент...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

Что происходит:

  1. Компонент не загружается до момента его реального использования
  2. Во время загрузки показывается fallback-контент
  3. После загрузки компонент кешируется

2. Именованный импорт

Для компонентов, экспортированных по имени:

const LazyComponent = lazy(() => import('./LazyComponent')
  .then(module => ({ default: module.LazyComponent })));

3. Предзагрузка компонентов

Для оптимизации UX можно предзагружать компоненты:

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

// Где-то в обработчике событий (например, при hover на кнопке)
function handleHover() {
  import('./LazyComponent');
}

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <LazyComponent />
    </Suspense>
  );
}

4. Групповая ленивая загрузка

Типичный пример для роутинга:

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

function App() {
  return (
    <Router>
      <Suspense fallback={<GlobalLoader />}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </Suspense>
    </Router>
  );
}

5. Каскадные Suspense

Разные fallback для разных частей приложения:

<Suspense fallback={<AppLoader />}>
  <Layout>
    <Suspense fallback={<SidebarLoader />}>
      <Sidebar />
    </Suspense>
    <MainContent>
      <Suspense fallback={<ContentLoader />}>
        <LazyComponent />
      </Suspense>
    </MainContent>
  </Layout>
</Suspense>

6. Обработка ошибок

Обязательно сочетайте с Error Boundary:

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error }) {
  return <div>Ошибка загрузки компонента: {error.message}</div>;
}

<ErrorBoundary FallbackComponent={ErrorFallback}>
  <Suspense fallback={<Loader />}>
    <LazyComponent />
  </Suspense>
</ErrorBoundary>

7. Оптимизации производительности

Задержка fallback

Чтобы избежать "мигания" лоадера при быстрой загрузке:

<Suspense fallback={<DelayedSpinner delay={300} />}>
  <LazyComponent />
</Suspense>

Где DelayedSpinner:

function DelayedSpinner({ delay }) {
  const [show, setShow] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => setShow(true), delay);
    return () => clearTimeout(timer);
  }, [delay]);

  return show ? <Spinner /> : null;
}

8. SSR и ленивая загрузка

Для Next.js/Gatsby используйте их встроенные решения:

// Next.js пример
import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(
  () => import('../components/LazyComponent'),
  {
    loading: () => <p>Загрузка...</p>,
    ssr: false // Отключить для SSR
  }
);

Лучшие практики

  1. Разбивайте на осмысленные чанки (по роутам, фичам)
  2. Используйте осмысленные fallback - скелетоны вместо спиннеров
  3. Избегайте избыточного вложения Suspense
  4. Предзагружайте при возможном взаимодействии пользователя

Резюмируем

React Suspense с ленивой загрузкой — мощный инструмент для:

  • Уменьшения начального размера бандла
  • Ускорения загрузки приложения
  • Улучшения пользовательского опыта

Используйте эту связку для больших приложений, но помните о необходимости:

  • Качественных fallback-состояний
  • Обработки ошибок через Error Boundary
  • Оптимизации моментов загрузки