React.Suspense — как он работает и зачем нужен
Разбираем на простых примерах. Почему Suspense появился, как им пользоваться сегодня и что он будет делать в будущем.
Зачем вообще нужен Suspense
В современном фронтенде почти всё грузится асинхронно:
- данные с сервера,
- тяжёлые компоненты,
- отдельные страницы или графики.
Проблема в том, что пока что-то не загрузилось, Reactу нужно что-то показать. Раньше это решали костылями: флаг loading
, if (!data) return <Spinner/>
, десятки useEffect
с fetch
.
Suspense
появился как универсальный способ решить эту задачу: покажи заглушку, пока часть интерфейса не готова.
Сегодня vs Suspense
Как пишем загрузку сегодня
function Profile({ id }) {
const [user, setUser] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
setLoading(true)
fetch(`/api/user/${id}`)
.then(res => res.json())
.then(data => {
setUser(data)
setLoading(false)
})
}, [id])
if (loading) return <div>Загрузка...</div>
return <div>{user.name}</div>
}
Минусы:
- вручную пишем стейт
loading
- дублируем лоадер в каждом компоненте
- легко забыть про обработку ошибок
Как решает Suspense (будущее API)
function Profile({ id }) {
const user = use(fetch(`/api/user/${id}`).then(res => res.json()))
return <div>{user.name}</div>
}
function App({ id }) {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<Profile id={id} />
</Suspense>
)
}
Разница:
- никаких флагов
loading
- Suspense сам знает, что данные ещё не готовы
- один
fallback
работает сразу для всего
⚠️ Важно: такой код с use
пока только экспериментальный. Но это показывает, куда движется React.
Как работает прямо сейчас
Lazy components
Самый базовый сценарий — это React.lazy
.
Допустим, у тебя есть тяжёлый компонент:
import { lazy } from "react"
const Heavy = lazy(() => import("./Heavy"))
function App() {
return <Heavy />
}
Так не сработает: пока идёт загрузка Heavy
, React не знает, что отрендерить.
Решение — обернуть его в Suspense
:
import { Suspense, lazy } from "react"
const Heavy = lazy(() => import("./Heavy"))
function App() {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<Heavy />
</Suspense>
)
}
Теперь:
- компонент грузится в фоне,
- React показывает
fallback
, - когда готов — рендерит реальный компонент.
Вложенные Suspense
Suspense
можно вкладывать друг в друга и делать разные заглушки для разных частей интерфейса:
<Suspense fallback={<div>Грузим всю страницу...</div>}>
<Header />
<Suspense fallback={<div>График ещё не готов...</div>}>
<Chart />
</Suspense>
<Footer />
</Suspense>
Пользователь видит страницу с хедером и футером, даже если график ещё догружается.
Code splitting
Suspense
+ React.lazy
= базовый инструмент разделения кода.
Ты можешь грузить куски приложения (страницы, виджеты) только тогда, когда они реально нужны.
Ограничения
На сегодня Suspense
умеет работать только с React.lazy и компонентами, но не напрямую с fetch
.
Если ты пишешь:
const data = fetch("/api/posts").then(res => res.json())
— Suspense
это не поймёт. Для данных приходится использовать сторонние либы (react-query
, Relay, SWR) или кастомные обёртки.
Будущее Suspense
React-команда двигает в сторону того, чтобы Suspense
стал стандартным способом работы с любыми асинхронными данными.
1. Новый хук use
(экспериментальный)
Идея простая: можно передавать промис прямо в компонент.
async function fetchUser(id) {
const res = await fetch(`/api/user/${id}`)
return res.json()
}
function Profile({ id }) {
const user = use(fetchUser(id))
return <div>{user.name}</div>
}
Если данные ещё не загрузились → Suspense
покажет fallback
.
Это пока только в канарейке, но будет частью React 19+.
2. React Server Components (RSC)
В Next.js 13/14 уже можно использовать серверные компоненты.
Они могут await fetch()
прямо в коде, а на клиенте Suspense
решает, что показывать, пока серверная часть не готова.
3. Transitions API
Уже есть в React 18.
Позволяет помечать обновления как “несрочные” (startTransition
) и вместе с Suspense
показывать скелетоны или индикаторы только на нужное время.
Когда использовать уже сейчас
- Ленивые компоненты (
React.lazy
) - Подгрузка тяжёлых страниц или графиков
- Разные заглушки для разных частей интерфейса (nested Suspense)
- Code splitting
Итог
- Сегодня Suspense = решение для ленивых компонентов
- Завтра Suspense = единый способ работы со всеми асинхронными данными в React
- Начни использовать его уже сейчас на ленивых компонентах → потом проще будет перейти к новому API
Suspense — это не "ещё один хук", а фундамент для будущего React. Если ты его понял — тебе будет проще разбираться в новых фичах (use
, RSC, transitions).