Потоковая передача¶
В предыдущей главе вы узнали о различных методах рендеринга в Next.js. Мы также обсудили, как медленное получение данных может повлиять на производительность вашего приложения. Давайте рассмотрим, как можно улучшить пользовательский опыт при медленных запросах данных.
Вот темы, которые мы рассмотрим
- Что такое потоковая передача и когда его можно использовать.
- Как реализовать потоковую передачу с помощью
loading.tsx
иSuspense
. - Что такое загрузочные скелетоны.
- Что такое Next.js Route Groups и когда их можно использовать.
- Где разместить границы React
Suspense
в вашем приложении.
Что такое потоковая передача?¶
Потоковая передача - это техника передачи данных, которая позволяет разбить маршрут на более мелкие «куски» и постепенно передавать их с сервера на клиент по мере готовности.
Потоковая передача позволяет предотвратить блокировку всей страницы медленными запросами данных. Это позволяет пользователю видеть части страницы и взаимодействовать с ними, не дожидаясь загрузки всех данных, прежде чем пользователю будет показан любой пользовательский интерфейс.
Потоковая передача хорошо работает с компонентной моделью React, так как каждый компонент можно рассматривать как чанк.
Существует два способа реализации потоковой передачи данных в Next.js:
- На уровне страницы, с помощью файла
loading.tsx
(который создает для вас<Suspense>
). - На уровне компонентов, с помощью
<Suspense>
для более детального контроля.
Давайте посмотрим, как это работает.
В чем одно из преимуществ потоковой передачи?
Потоковая передача всей страницы с помощью loading.tsx
.¶
В папке /app/dashboard
создайте новый файл с именем loading.tsx
:
/app/dashboard/loading.tsx | |
---|---|
1 2 3 |
|
Обновите http://localhost:3000/dashboard, и теперь вы должны увидеть:
Здесь происходит несколько вещей:
loading.tsx
- это специальный файл Next.js, построенный поверх React Suspense. Он позволяет создавать резервный пользовательский интерфейс, который будет отображаться в качестве замены во время загрузки содержимого страницы.- Поскольку
<SideNav>
статичен, он показывается сразу. Пользователь может взаимодействовать с<SideNav>
, пока загружается динамический контент. - Пользователю не нужно ждать окончания загрузки страницы, чтобы перейти на другую (это называется прерывистой навигацией).
Поздравляем! Вы только что реализовали потоковую передачу. Но мы можем сделать еще больше для улучшения пользовательского опыта. Давайте покажем скелетон загрузки вместо текста Loading...
.
Добавление скелетонов загрузки¶
Загрузочный скелетон - это упрощенная версия пользовательского интерфейса. Многие веб-сайты используют их в качестве заполнителя (или запасного варианта), чтобы указать пользователям, что содержимое загружается. Любой пользовательский интерфейс, который вы добавите в loading.tsx
, будет встроен как часть статического файла и отправлен первым. Затем остальной динамический контент будет передан с сервера на клиент.
Внутри файла loading.tsx
импортируйте новый компонент под названием <DashboardSkeleton>
:
/app/dashboard/loading.tsx | |
---|---|
1 2 3 4 5 |
|
Затем обновите http://localhost:3000/dashboard, и теперь вы должны увидеть:
Исправление ошибки скелета загрузки с группами маршрутов¶
Сейчас ваш загрузочный скелет будет применяться к счетам.
Поскольку loading.tsx
находится на уровень выше, чем /invoices/page.tsx
и /customers/page.tsx
в файловой системе, он также применяется к этим страницам.
Мы можем изменить это с помощью Route Groups. Создайте новую папку /(overview)
внутри папки дашборда. Затем переместите файлы loading.tsx
и page.tsx
в эту папку:
Теперь файл loading.tsx
будет применяться только к странице обзора дашборда.
Группы маршрутов позволяют организовывать файлы в логические группы, не затрагивая структуру URL-путей. Когда вы создаете новую папку, используя круглые скобки ()
, ее название не будет включено в путь URL. Таким образом, /dashboard/(overview)/page.tsx
превращается в /dashboard
.
Здесь вы используете группу маршрутов для того, чтобы loading.tsx
применялся только к странице обзора дашборда. Однако вы также можете использовать группы маршрутов для разделения приложения на секции (например, маршруты (маркетинг)
и маршруты (магазин)
) или на команды для больших приложений.
Потоковая передача компонента¶
До сих пор вы передавали всю страницу. Но вы также можете быть более детализированными и передавать определенные компоненты с помощью React Suspense.
Suspense позволяет откладывать отрисовку частей приложения до тех пор, пока не будет выполнено какое-то условие (например, загружены данные). Вы можете обернуть свои динамические компоненты в Suspense. Затем передайте ему резервный компонент, который будет отображаться, пока динамический компонент загружается.
Если вы помните медленный запрос данных, fetchRevenue()
, то именно этот запрос замедляет работу всей страницы. Вместо того чтобы блокировать всю страницу, вы можете использовать Suspense для потоковой передачи только этого компонента и немедленного показа остальной части пользовательского интерфейса страницы.
Для этого вам нужно будет переместить выборку данных в компонент, давайте обновим код, чтобы увидеть, как это будет выглядеть:
Удалите все экземпляры fetchRevenue()
и его данные из /dashboard/(overview)/page.tsx
:
/app/dashboard/(overview)/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Затем импортируйте <Suspense>
из React и оберните его вокруг <RevenueChart />
. Вы можете передать ему компонент возврата под названием <RevenueChartSkeleton>
.
/app/dashboard/(overview)/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
Наконец, обновите компонент <RevenueChart>
, чтобы получить свои собственные данные и удалить переданный ему параметр:
/app/ui/dashboard/revenue-chart.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Теперь обновите страницу, вы должны увидеть информацию дашборда почти сразу, в то время как для <RevenueChart>
будет показан скелет резервного копирования:
Практика: Потоковая передача <LatestInvoices>
.¶
Теперь ваша очередь! Отработайте то, чему вы только что научились, выполнив потоковую передачу компонента <LatestInvoices>
.
Переместите fetchLatestInvoices()
вниз со страницы на компонент <LatestInvoices>
. Заверните компонент в границу <Suspense>
с фаллабетом <LatestInvoicesSkeleton>
.
Когда все будет готово, разверните тумблер, чтобы увидеть код решения:
Reveal the solution
Dashboard Page:
/app/dashboard/(overview)/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|
<LatestInvoices>
component. Remember to remove the props from the component:
/app/ui/dashboard/latest-invoices.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Группировка компонентов¶
Отлично! Вы почти у цели, теперь вам нужно обернуть компоненты <Card>
в Suspense. Вы можете получить данные для каждой отдельной карты, но это может привести к эффекту «выпрыгивания» при загрузке карт, что может визуально раздражать пользователя.
Как же решить эту проблему?
Чтобы создать эффект «ступенчатости», вы можете сгруппировать карточки с помощью компонента-обертки. Это означает, что сначала будет показан статический <SideNav/>
, затем карточки и т. д.
В файле page.tsx
:
- Удалите компоненты
<Card>
. - Удалите функцию
fetchCardData()
. - Импортируйте новый компонент обертки под названием
<CardWrapper />
. - Импортируйте новый скелетон компонента под названием
<CardsSkeleton />
. - Оберните
<CardWrapper />
в Suspense.
/app/dashboard/(overview)/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Затем перейдите в файл /app/ui/dashboard/cards.tsx
, импортируйте функцию fetchCardData()
и вызовите ее внутри компонента <CardWrapper/>
. Не забудьте откомментировать весь необходимый код в этом компоненте.
/app/ui/dashboard/cards.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
Обновите страницу, и вы увидите, что все карты загружаются одновременно. Вы можете использовать этот шаблон, когда хотите, чтобы несколько компонентов загружались одновременно.
Решение о том, где расположить границы приостановки¶
Место расположения границ Suspense зависит от нескольких факторов:
- Как вы хотите, чтобы пользователь воспринимал страницу во время ее загрузки.
- Какому контенту вы хотите отдать предпочтение.
- Если компоненты зависят от получения данных.
Посмотрите на свою страницу дашборда, есть ли что-то, что вы сделали бы по-другому?
Не волнуйтесь. Здесь нет правильного ответа.
- Вы могли бы транслировать всю страницу, как мы сделали с
loading.tsx
... но это может привести к увеличению времени загрузки, если один из компонентов медленно получает данные. - Можно транслировать каждый компонент по отдельности... но это может привести к тому, что пользовательский интерфейс будет «выскакивать» на экран по мере готовности.
- Можно также создать эффект стаггирования, передавая потоком разделы страницы. Но вам придется создавать компоненты-обертки.
Место, где вы разместите границы Suspense, зависит от вашего приложения. В целом, хорошей практикой является перемещение поиска данных вниз к компонентам, которым они нужны, а затем обертывание этих компонентов в Suspense. Но нет ничего плохого в потоковой передаче секций или всей страницы, если это необходимо вашему приложению.
Не бойтесь экспериментировать с Suspense и смотреть, что работает лучше, это мощный API, который поможет вам создать более восхитительный пользовательский опыт.
В целом, что считается хорошей практикой при работе с Suspense и получением данных?
Заглядывая в будущее¶
Потоковая передача и серверные компоненты дают нам новые способы обработки состояний получения и загрузки данных, в конечном итоге направленные на улучшение качества работы конечного пользователя.
В следующей главе вы узнаете о Partial Prerendering, новой модели рендеринга Next.js, созданной с учетом потоковой обработки.
Источник — https://nextjs.org/learn/dashboard-app/streaming