Как реализовать загрузку контента в Suspense?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Реализация загрузки контента в React Suspense
React Suspense — это механизм для декларативной обработки состояний загрузки в React-приложениях. Он позволяет компонентам "ожидать" (suspend) данные, промисы или другие ресурсы, пока они не будут готовы к рендерингу. Вот как правильно реализовать загрузку контента с использованием Suspense.
Основные концепции Suspense
Suspense работает в связке с несколькими ключевыми элементами:
- Компонент Suspense — оборачивает компоненты, которые могут находиться в состоянии загрузки
- Fallback-проп — компонент, который отображается во время ожидания
- Ресурсы с поддержкой Suspense — данные или промисы, которые могут "приостанавливать" рендеринг
Практическая реализация
1. Базовый пример с ленивой загрузкой компонентов
import React, { Suspense, lazy } from 'react';
// Ленивая загрузка компонента
const LazyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Загрузка компонента...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
2. Создание ресурсов с поддержкой Suspense
Для работы с данными нужно создать обертку, которая бросает промис при попытке чтения данных:
// Создаем кэш для ресурсов
function createResource(promise) {
let status = 'pending';
let result;
const suspender = promise.then(
(data) => {
status = 'success';
result = data;
},
(error) => {
status = 'error';
result = error;
}
);
return {
read() {
if (status === 'pending') {
throw suspender; // React перехватывает это и показывает fallback
}
if (status === 'error') {
throw result; // Можно обработать через Error Boundary
}
return result;
}
};
}
// Использование ресурса
const userResource = createResource(fetchUserData());
3. Интеграция с современными библиотеками
Современные библиотеки для управления состоянием имеют встроенную поддержку Suspense:
// Использование с React Query
import { useSuspenseQuery } from '@tanstack/react-query';
function UserProfile({ userId }) {
const { data } = useSuspenseQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
});
return <div>{data.name}</div>;
}
// Обертка в Suspense
function App() {
return (
<Suspense fallback={<UserProfileSkeleton />}>
<UserProfile userId="123" />
</Suspense>
);
}
4. Каскадные Suspense и Error Boundaries
import { Suspense } from 'react';
import ErrorBoundary from './ErrorBoundary';
function Dashboard() {
return (
<ErrorBoundary fallback={<ErrorDisplay />}>
<Suspense fallback={<HeaderSkeleton />}>
<DashboardHeader />
<Suspense fallback={<ContentSkeleton />}>
<DashboardContent />
<Suspense fallback={<SidebarSkeleton />}>
<DashboardSidebar />
</Suspense>
</Suspense>
</Suspense>
</ErrorBoundary>
);
}
Ключевые паттерны и лучшие практики
Приоритизация загрузки
Используйте startTransition для разделения срочных и несрочных обновлений:
import { startTransition, Suspense, useState } from 'react';
function SearchComponent() {
const [query, setQuery] = useState('');
const handleChange = (e) => {
const value = e.target.value;
setQuery(value); // Срочное обновление
startTransition(() => {
// Несрочное обновление с Suspense
setSearchQuery(value);
});
};
return (
<div>
<input value={query} onChange={handleChange} />
<Suspense fallback={<ResultsSkeleton />}>
<SearchResults query={searchQuery} />
</Suspense>
</div>
);
}
Предзагрузка ресурсов
// Предзагрузка данных до рендеринга
const preloadResource = (url) => {
const resource = createResource(fetch(url));
resource.read(); // Начинаем загрузку
return resource;
};
// Использование в компоненте
const userData = preloadResource('/api/user/123');
Распространенные ошибки и их решение
- Отсутствие Error Boundary — всегда оборачивайте Suspense в Error Boundary для обработки ошибок
- Неправильное расположение Suspense — Suspense должен находиться выше компонента, который использует ресурс
- Избыточные fallback — избегайте вложенных Suspense с одинаковыми fallback
Современные подходы (React 18+)
С React 18 появились новые возможности:
// Streaming SSR с Suspense
import { renderToPipeableStream } from 'react-dom/server';
// Селективные гидратации
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
<Suspense fallback={<Spinner />}>
<RelatedPosts />
</Suspense>
Заключение
Suspense — это мощная абстракция для управления асинхронными операциями в React. Ключевые преимущества включают декларативный синтаксис, интеграцию с Concurrent Features, и улучшенный UX за счет управляемых состояний загрузки. Для максимальной эффективности комбинируйте Suspense с современными библиотеками данных (React Query, SWR, Apollo) и используйте в связке с Error Boundaries для полноценной обработки всех состояний приложения.