Command Palette

Search for a command to run...

GitHub
Блог
Next

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).