Загрузка данных вне Effects, Suspense, use, transitions, useDeferredValue, streaming и проектирование состояний ожидания.
Асинхронность — это не spinner, а согласованная модель приоритета, пустых данных, ошибок, повторов и устаревшего содержимого.
Вы выберете data boundary, построите Suspense/error/pending UI и сохраните отзывчивость при несрочных обновлениях.
До начала достаточно Promise, Actions, Effects, state machines и concurrent render. В конце должен появиться не конспект, а поиск каталога с route data, Suspense, stale content indicator, transition и retry.
Fetch в Effect начинается после первого commit и часто создаёт цепочку parent render → fetch → child render → fetch. Route loader или framework data API стартует работу до/вместе с render, умеет отмену навигации и координирует ошибки. Effect остаётся для внешней синхронизации, а не универсального data fetching.
Рабочая проверка. Сравните network waterfall Effect-страницы и параллельных route loaders.
Типичная поломка. Каждый компонент загружает обязательные данные после mount.
Когда descendant suspends, ближайший Suspense показывает fallback. Boundary выбирают по пользовательскому skeleton и reveal sequence, а не оборачивают каждый текст. Повторное suspension уже показанного content может скрыть его, если обновление не transition; router/framework обычно координирует это.
Рабочая проверка. Разместите boundary вокруг независимой панели, сохранив общий header видимым.
Типичная поломка. Один fullscreen spinner на всё приложение при любой мелкой загрузке.
use и стабильный Promiseuse читает Promise или Context и может вызываться условно, в отличие от Hooks состояния, но всё равно только из component/Hook. Pending Promise suspends, fulfilled возвращает значение, rejected передаёт ошибку boundary. Создавайте Promise в loader/server/cache, а не заново в client render.
Рабочая проверка. Передайте Promise от loader в client component и прочитайте через use.
Типичная поломка. use(fetch(url)) создаёт новый запрос на каждый повтор render.
startTransition маркирует state updates как несрочные и interruptible. Async function внутри transition поддерживается, но updates после await в некоторых сценариях требуют новой startTransition. Controlled input update нельзя делать transition: поле должно отражать ввод немедленно.
Рабочая проверка. Оставьте query срочным, а навигацию/результаты выполните transition.
Типичная поломка. Transition вокруг setter value input.
useDeferredValue и stale contentDeferred value отстаёт от срочного source и позволяет тяжёлому subtree обновиться позже. Это не фиксированный debounce и не уменьшает число network requests само по себе. Пользователь должен видеть, что список устарел: dimming или статус, не ложное ощущение соответствия новому query.
Рабочая проверка. Покажите opacity для query !== deferredQuery и проверьте accessible status.
Типичная поломка. Показывать старые результаты как будто они соответствуют новому запросу.
Async resource failure требует ближайшей error boundary с безопасным сообщением и retry/reset. Boundary не ловит ошибки event handlers и произвольного async callback автоматически; их обработка относится к handler/action. Reset должен инвалидировать ресурс или navigation key, иначе тот же rejected cache немедленно упадёт снова.
Рабочая проверка. Сделайте retry, создающий новую попытку ресурса, а не только скрывающий error UI.
Типичная поломка. Кнопка retry просто setError(null), не меняя rejected resource.
Server streaming отправляет shell и последующие части по готовности Suspense boundaries. Это уменьшает время до полезного HTML, но не лечит медленный backend и требует стабильного layout. Граница с критичными SEO/heading данными выбирается иначе, чем below-the-fold рекомендации.
Рабочая проверка. Спроектируйте shell, critical content и поздний secondary boundary.
Типичная поломка. Поместить заголовок и весь основной контент за медленной вторичной рекомендацией.
Минимум различайте initial pending, empty success, content success, refresh/stale, validation failure, recoverable system failure и unauthorized/not-found. Spinner без контекста часто недостаточен. Каждый state имеет действие пользователя и accessibility announcement; не очищайте полезные данные при фоновом refresh без причины.
Рабочая проверка. Составьте state table и screenshot/test для каждого исхода.
Типичная поломка. data ? list : spinner бесконечно показывает spinner для пустого массива.
Реализуйте страницу поиска: loader запускает запрос до render, результаты читаются через use, fallback соответствует layout, смена фильтра идёт transition, прежний список dimmed через deferred query, ошибки восстанавливаются retry.
Критерий завершения: нет fetch waterfall из Effects, срочный ввод не блокируется, а empty/error/pending/stale состояния различимы и протестированы. Сначала зафиксируйте наблюдаемое поведение тестом или измерением, затем меняйте реализацию.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.
Далее: Маршрутизация и data routers