Гид по технологиям

Loading UIs в Next.js 13 с React Suspense

6 min read Frontend Обновлено 12 Apr 2026
Loading UIs в Next.js 13 с React Suspense
Loading UIs в Next.js 13 с React Suspense

Ноутбук на сером столе с открытым редактором кода, экран показывает двухколоночный код.

Загрузочные интерфейсы и визуальные индикаторы — важная часть веб‑ и мобильных приложений. Без них пользователи не понимают, работает ли приложение, выполнён ли их запрос и происходит ли обработка их действий. Чёткие индикаторы снижают неопределённость и уменьшают число преждевременных выходов из приложения.

Влияние загрузочных интерфейсов на производительность и UX

Правило видимости текущего состояния системы (одно из эвристик Якоба Нильсена) подчёркивает необходимость своевременной обратной связи от интерфейса. Загрузочные UI сообщают пользователю, что приложение занято, и делают это в нужные сроки.

С технической точки зрения правильно реализованные загрузочные экраны улучшают восприятие скорости. При асинхронной подгрузке контента страница не «замерзает» целиком — отдельные части обновляются в фоне. Это создаёт ощущение плавности и повышает терпение пользователя.

Дизайнер работает над монохромным UX/UI на компьютере.

Практическое правило: показывайте визуальный индикатор до тех пор, пока часть интерфейса не готова к взаимодействию. Это увеличивает шансы, что пользователь дождётся результата вместо принудительного обновления страницы или закрытия вкладки.

Краткое объяснение: что такое React Suspense

React Suspense — это компонент для управления асинхронными ресурсами в дереве компонентов. Он отображает fallback (запасной) UI до тех пор, пока дочерний компонент не завершит загрузку данных или не станет готов к отображению.

Определение: Suspense — контейнер, который ожидает завершения асинхронных операций и подменяет содержимое резервным интерфейсом.

Пример использования (сохраняем код оригинально):

export default function Todos() {  
  const  data = fetchData() {  
    //fetch data...  
    return data;  
  };  
  return 

{data.title}

} // the fallback component export default function Loading() {   return 

Loading data ...

}

Suspense будет показывать компонент Loading, пока Todos не станет готов. Синтаксис обёртки выглядит так:

import { Suspense } from 'react';  
  
function App() {  
  return (  
    <>  
      }>  
          
        
      
  );}

Поддержка React Suspense в Next.js 13

Next.js 13 представил поддержку Suspense через новую структуру приложения (app directory). В папке маршрута можно создать файл loading.js — Next.js автоматически использует его как fallback для соответствующего сегмента приложения.

Дальше мы пройдём шаги по созданию простого To‑Do приложения, чтобы увидеть Suspense в действии.

Создаём проект Next.js 13

Мы будем получать список задач (todos) с API DummyJSON. Для старта выполните:

npx create-next-app@latest next-project --experimental-app

Создаём маршрут Todos

Внутри src/app создайте папку Todos и в ней файл page.js с таким содержимым (сохранён исходный код):

async function Todos() {  
  
  async function fetchTodos() {  
    let res = await fetch("https://dummyjson.com/todos");  
    const todosData =  await res.json();  
    return todosData  
  }  
  
  const {todos} = await fetchTodos();  
  
  async function wait(ms) {  
    return new Promise(resolve => setTimeout(resolve, ms));  
  }  
  
  await wait(3000);   
  
  return (  
    <>   
      
        
          {todos.slice(0, 10).map((todo) => (             
                  
                    
  • {todo.todo}

  •               
                
          ))}         
      
       ); } export default Todos;

Описание: Todos получает массив задач и рендерит первые 10. Функция wait имитирует задержку, чтобы пользователь увидел loading UI. В реальном мире задержки появляются из‑за сетевых запросов, обработки на сервере, медленных API или работы с базой данных.

Интеграция React Suspense в приложение Next.js

Откройте app/layout.js и замените шаблон на следующий код:

import React, { Suspense } from 'react';  
import Loading from '@/app/Todos/loading';  
  
export const metadata = {  
  title: 'Create Next App',  
  description: 'Generated by create next app',  
}  
  
export default function RootLayout({ children }) {  
  return (  
      
        
      }>  
            {children}  
        
        
      
  )  
}

Здесь Suspense охватывает children — то есть весь интерфейс становится потенциально «подвешиваемым», и loading.js будет показываться при ожидании любых асинхронных частей.

Обновление домашней страницы

Замените app/page.js на этот код:

import React from 'react';  
import Link from "next/link";  
  
function Home () {  
  return (  
    
      
        

Next.js 13 React Suspense Loading Example

        Get Todos       
    
  ) } export default Home;

Создаём loading.js

В app/Todos создайте loading.js с базовой разметкой:

export default function Loading() {  
  return 

Loading data ...

}

Этого достаточно, чтобы Next.js показывал запасной UI при загрузке сегмента.

Добавление современных спиннеров и скелетонов

Базовый loading UI можно улучшить двумя путями:

  • Скелетоны — показывают каркас контента: заголовки, абзацы, карточки. Они создают иллюзию незавершённого, но предсказуемого контента.
  • Анимированные индикаторы (спиннеры) — дают понять, что идёт процесс.

Пример с библиотекой react-loader-spinner:

Установите пакет:

npm install react-loader-spinner --save

Обновите loading.js:

"use client"  
import { RotatingLines} from'react-loader-spinner'  
  
function Loading() {  
  return (  
    
      

Loading the Todos ...

           
  ); } export default Loading;

Добавление анимаций делает ожидание более терпимым. Альтернатива — кастомные CSS‑скелетоны с Tailwind или CSS Modules.

Руководство для команд: роль‑ориентированные чек‑листы

Разделим задачи по ролям, чтобы обеспечить слаженную работу над загрузочными интерфейсами.

  • Разработчик:

    • Добавить Suspense и loading.js для ключевых маршрутов.
    • Не блокировать главный поток рендера; выносить тяжёлые операции в асинхронные функции.
    • Обработать ошибки (Error Boundary) рядом с Suspense.
  • Дизайнер:

    • Создать скелетоны, соответствующие реальной структуре контента.
    • Предусмотреть состояние пустого результата, ошибку и успешную загрузку.
  • QA:

    • Проверить показ loading UI при медленном соединении (throttling).
    • Тестировать поведение при отмене запросов и при повторной попытке.
  • PM/PO:

    • Утвердить критерии приёмки и целевые сценарии, где требуется видимый индикатор.

Критерии приёмки

  • При медленном соединении пользователь видит loading.js или скелетон в течение всей задержки.
  • Основные интерактивные элементы не доступны до их полной готовности (если это предусмотрено), а состояние отображается корректно.
  • Ошибки и пустые ответы показывают информативный UI (со ссылкой на повторы или инструкции).
  • Визуальные индикаторы соответствуют дизайну и не «мигают» при быстрой загрузке.

Тест‑кейсы и примеры приёмки

  1. Включить Network Throttling (Slow 3G). Перейти на /Todos. Ожидается показ loading UI минимум 2–3 секунды.
  2. Симулировать ошибку API (код 500). Проверить, что отображается сообщение об ошибке и кнопка «Повторить».
  3. Быстрая загрузка: переход назад/вперед в истории браузера не должен показывать видимый «мигающий» скелетон.
  4. Мобильный viewport: элементы скелетона не вылазят за экран и сохраняют читаемость.

Когда подход с Suspense не подходит

  • Если ваши асинхронные операции тесно связаны с imperative API, где нужен точный контроль тайминга и отмены, возможно, потребуется ручная реализация состояния загрузки.
  • Если проект использует устаревшую архитектуру без поддержки app directory, миграция может быть затратной.
  • Для некоторых критичных UX‑сцен требуется мгновенная доступность минимального набора данных — тогда нужен продуманный приоритет загрузки (data streaming) вместо полного Suspense‑блокирования.

Альтернативные подходы

  • Локальные индикаторы состояния (useState + isLoading) для простых компонентов.
  • Streaming и incremental rendering (Edge functions, Server‑Side Rendering с частичной подгрузкой).
  • Комбинация: Suspense для крупных сегментов + локальные индикаторы для микросекций.

Mini‑методология внедрения (пошагово)

  1. Проанализировать ключевые маршруты и определить, где пользователь видит пустой экран.
  2. Добавить loading.js для каждого проблемного сегмента.
  3. Внедрить скелетоны, соответствующие реальной структуре данных.
  4. Протестировать на медленных соединениях и в браузерах.
  5. Добавить метрики (время до первого полезного контента) и отслеживать изменения.

Факт‑бокс

  • Suspense встраивается на уровне компонентов и маршрутов.
  • loading.js — файл, используемый Next.js для показа fallback для конкретного сегмента.
  • Сквозная интеграция требует Error Boundary рядом с Suspense.

Шаблон для loading.js (рекомендация)

  • Показывайте скелетон, похожий на будущий контент (заголовки, строки текста, карточки).
  • Не используйте агрессивную анимацию, которая отвлекает от основной задачи.
  • Предусмотрите aria‑атрибуты для доступности (role=”status”, aria-live=”polite”).

Пример доступного контейнера:

export default function Loading() {
  return (
    

Загрузка данных...

{/* здесь ваш спиннер или скелетон */}
); }

Безопасность и приватность

  • Не показывайте в loading UI чувствительные данные, пока они не загружены и не проверены.
  • Логируйте только технические метрики загрузки; не включайте персональные данные в логи.

Миграция и совместимость

  • Для перехода с pages → app directory планируйте миграцию по этапам: сначала общая обёртка layout.js, затем поочерёдная миграция маршрутов.
  • Проверяйте совместимость сторонних библиотек, которые ожидают клиентский рендер.

Пример decision tree (упрощённый)

flowchart TD
  A[Нужен индикатор загрузки?] -->|Да| B{Асинхронность на уровне сервера?}
  B -->|Да| C[Использовать Suspense + loading.js]
  B -->|Нет| D[Локальный isLoading / state]
  C --> E{Нужно отображать скелетон?}
  E -->|Да| F[Создать скелетон по макету]
  E -->|Нет| G[Показать простой спиннер]

Риски и смягчения

  • Риск: «мигание» загрузочного UI при быстрой загрузке. Смягчение: добавлять небольшую задержку‑порог (например, 200–300 мс) перед показом скелетона.
  • Риск: большие bundle‑размеры для анимированных спиннеров. Смягчение: ленивый импорт библиотек (dynamic import) или использование CSS‑анимаций.

Короткое резюме

Loading UIs повышают доверие пользователя и делают асинхронные операции более предсказуемыми. React Suspense в Next.js 13 упрощает добавление запасного интерфейса через loading.js. Планируйте дизайн скелетонов, тестируйте на медленных сетях и применяйте роль‑ориентированные чек‑листы, чтобы внедрить решение без регрессий.

Important: добавляйте Error Boundary рядом с Suspense и тестируйте поведение при ошибках сети.

Заметки: выбор между скелетоном и спиннером определяется сложностью интерфейса и ожиданиями пользователей.


Краткие рекомендации для публикации в соцсетях:

  • OG title: Loading UIs в Next.js 13 с React Suspense
  • OG description: Пошаговое руководство: как встроить loading.js, добавить скелетоны и спиннеры, улучшить UX при асинхронной загрузке.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

less, more и most: читать файлы в терминале
Linux

less, more и most: читать файлы в терминале

Удаление дубликатов на Samsung — My Files
Android.

Удаление дубликатов на Samsung — My Files

Макрофотография: руководство для начинающих
Фотография

Макрофотография: руководство для начинающих

Управление подписками Xbox на Series X|S
Xbox

Управление подписками Xbox на Series X|S

Фото iPhone в стиле Instagram
Фото

Фото iPhone в стиле Instagram

Управление приоритетом процессов в Linux
Linux

Управление приоритетом процессов в Linux