Получение данных¶
Теперь, когда вы создали и засеяли свою базу данных, давайте обсудим различные способы получения данных для вашего приложения и построим обзорную страницу дашборда.
Вот темы, которые мы рассмотрим
- Узнайте о некоторых подходах к получению данных: API, ORM, SQL и т. д.
- Как серверные компоненты могут помочь вам получить более безопасный доступ к внутренним ресурсам.
- Что такое сетевые водопады.
- Как реализовать параллельную выборку данных с помощью JavaScript-паттерна.
Выбор способа получения данных¶
Слой API¶
API - это промежуточный слой между кодом вашего приложения и базой данных. Есть несколько случаев, когда вы можете использовать API:
- Если вы используете сторонние сервисы, которые предоставляют API.
- Если вы получаете данные от клиента, вам нужен слой API, работающий на сервере, чтобы не раскрывать клиенту секреты вашей базы данных.
В Next.js вы можете создавать конечные точки API с помощью Route Handlers.
Запросы к базе данных¶
При создании приложения полного стека вам также потребуется написать логику для взаимодействия с базой данных. Для реляционных баз данных, таких как Postgres, вы можете сделать это с помощью SQL или ORM.
Есть несколько случаев, когда вам придется писать запросы к базе данных:
- При создании конечных точек API вам нужно написать логику для взаимодействия с базой данных.
- Если вы используете React Server Components (получение данных на сервере), вы можете пропустить слой API и запрашивать базу данных напрямую, не рискуя раскрыть секреты базы данных клиенту.
В каком из этих сценариев не следует напрямую запрашивать базу данных?
Давайте узнаем больше о серверных компонентах React.
Использование серверных компонентов для получения данных¶
По умолчанию приложения Next.js используют React Server Components. Получение данных с помощью серверных компонентов - относительно новый подход, и у его использования есть несколько преимуществ:
- Серверные компоненты поддерживают JavaScript Promises, предоставляя решение для асинхронных задач, таких как получение данных. Вы можете использовать синтаксис
async/await
, не нуждаясь вuseEffect
,useState
или других библиотеках для получения данных. - Серверные компоненты работают на сервере, поэтому вы можете хранить дорогостоящие операции по выборке данных и логику на сервере, отправляя клиенту только результат.
- Поскольку серверные компоненты работают на сервере, вы можете запрашивать базу данных напрямую, без дополнительного уровня API. Это избавляет вас от необходимости писать и поддерживать дополнительный код.
В чем одно из преимуществ использования компонентов React Server для получения данных?
Использование SQL¶
Для вашего приложения дашборда вы будете писать запросы к базе данных с помощью библиотеки postgres.js и SQL. Есть несколько причин, по которым мы будем использовать SQL:
- SQL является промышленным стандартом для запросов к реляционным базам данных (например, ORM генерируют SQL под капотом).
- Базовое понимание SQL может помочь вам понять основы реляционных баз данных, что позволит вам применить свои знания в других инструментах.
- SQL универсален и позволяет получать конкретные данные и манипулировать ими.
- Библиотека
postgres.js
обеспечивает защиту от SQL-инъекций.
Не волнуйтесь, если вы раньше не использовали SQL - мы подготовили для вас запросы.
Перейдите к файлу /app/lib/data.ts
. Здесь вы увидите, что мы используем postgres
. Функция sql
function позволяет запросить базу данных:
/app/lib/data.ts | |
---|---|
1 2 3 4 5 6 7 |
|
Вы можете вызвать sql
в любом месте на сервере, как и серверный компонент. Но чтобы вам было проще ориентироваться в компонентах, мы сохранили все запросы к данным в файле data.ts
, и вы можете импортировать их в компоненты.
Что позволяет делать SQL в плане получения данных?
Если в главе 6 вы использовали собственный провайдер баз данных, вам нужно будет обновить запросы к базе данных, чтобы они работали с вашим провайдером. Запросы можно найти в файле /app/lib/data.ts
.
Получение данных для страницы обзора дашборда¶
Теперь, когда вы поняли различные способы получения данных, давайте получим данные для страницы обзора дашборда. Перейдите в /app/dashboard/page.tsx
, вставьте следующий код и потратьте некоторое время на его изучение:
/app/dashboard/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 |
|
Код выше намеренно закомментирован. Теперь мы начнем приводить примеры каждой части.
page
- это серверный компонент async. Он позволяет использоватьawait
для получения данных.- Также есть 3 компонента, которые получают данные:
<Card>
,<RevenueChart>
и<LatestInvoices>
. В настоящее время они закомментированы и пока не реализованы.
Получение данных для <RevenueChart/>
.¶
Чтобы получить данные для компонента <RevenueChart/>
, импортируйте функцию fetchRevenue
из data.ts
и вызовите ее внутри вашего компонента:
/app/dashboard/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
Далее сделаем следующее:
- Откомментируйте компонент
<RevenueChart/>
. - Перейдите к файлу компонента (
/app/ui/dashboard/revenue-chart.tsx
) и откомментируйте код внутри него. - Проверьте
localhost:3000
и вы должны увидеть график, использующий данныеrevenue
.
Давайте продолжим импортировать больше данных и отображать их на дашборде.
Получение данных для <LatestInvoices/>
¶
Для компонента <LatestInvoices />
нам нужно получить 5 последних счетов-фактур, отсортированных по дате.
Вы можете получить все счета и отсортировать их с помощью JavaScript. Это не проблема, поскольку наши данные невелики, но по мере роста вашего приложения может значительно увеличиться объем данных, передаваемых при каждом запросе, и JavaScript, необходимый для их сортировки.
Вместо того чтобы сортировать последние счета в памяти, вы можете использовать SQL-запрос, чтобы получить только 5 последних счетов. Например, вот SQL-запрос из вашего файла data.ts
:
/app/lib/data.ts | |
---|---|
1 2 3 4 5 6 7 |
|
На своей странице импортируйте функцию fetchLatestInvoices
:
/app/dashboard/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Затем откомментируйте компонент <LatestInvoices />
. Вам также нужно будет откомментировать соответствующий код в самом компоненте <LatestInvoices />
, расположенном по адресу /app/ui/dashboard/latest-invoices
.
Если вы зайдете на свой localhost
, то увидите, что из базы данных возвращаются только последние 5
. Надеюсь, вы начинаете понимать преимущества прямого запроса к базе данных!
Практика: Получение данных для компонентов <Card>
¶
Теперь настала ваша очередь получить данные для компонентов <Card>
. На карточках будут отображаться следующие данные:
- Общая сумма собранных счетов.
- Общая сумма счетов, ожидающих оплаты.
- Общее количество счетов-фактур.
- Общее количество клиентов.
Опять же, у вас может возникнуть соблазн получить все счета и клиентов и использовать JavaScript для работы с данными. Например, вы можете использовать Array.length
для получения общего количества счетов и клиентов:
1 2 |
|
Но с помощью SQL вы можете получить только те данные, которые вам нужны. Это немного дольше, чем использование Array.length
, но это означает, что во время запроса нужно передать меньше данных. Это альтернатива SQL:
/app/lib/data.ts | |
---|---|
1 2 |
|
Функция, которую вам нужно импортировать, называется fetchCardData
. Вам нужно будет деструктурировать значения, возвращаемые функцией.
Подсказка
- Проверьте компоненты карты, чтобы узнать, какие данные им нужны.
- Проверьте файл
data.ts
, чтобы увидеть, что возвращает функция.
Когда все будет готово, разверните тумблер ниже, чтобы увидеть окончательный код:
Раскрыть решение
/app/dashboard/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 |
|
Отлично! Теперь вы получили все данные для страницы обзора дашборда. Ваша страница должна выглядеть следующим образом:
Однако... есть две вещи, о которых вы должны знать:
- Запросы данных непреднамеренно блокируют друг друга, создавая водопад запросов.
- По умолчанию Next.js предусматривает маршруты для повышения производительности, это называется Static Rendering. Таким образом, если ваши данные изменятся, они не будут отражены в дашборде.
Давайте обсудим номер 1 в этой главе, а затем подробно рассмотрим номер 2 в следующей главе.
Что такое водопад запросов?¶
Под «водопадом» понимается последовательность сетевых запросов, зависящих от завершения предыдущих запросов. В случае с получением данных каждый запрос может начаться только после того, как предыдущий запрос вернет данные.
Например, нам нужно дождаться выполнения fetchRevenue()
, прежде чем fetchLatestInvoices()
сможет начать работу, и так далее.
/app/dashboard/page.tsx | |
---|---|
1 2 3 4 5 6 7 8 |
|
Такая схема не обязательно плоха. Бывают случаи, когда водопады нужны, потому что вы хотите, чтобы условие было выполнено до того, как вы сделаете следующий запрос. Например, сначала нужно получить идентификатор пользователя и информацию о его профиле. Получив идентификатор, можно перейти к получению списка его друзей. В этом случае каждый запрос зависит от данных, полученных от предыдущего запроса.
Однако такое поведение может быть непреднамеренным и влиять на производительность.
Когда вам может понадобиться узор «водопад»?
Параллельная выборка данных¶
Распространенный способ избежать водопада - инициировать все запросы данных одновременно - параллельно.
В JavaScript вы можете использовать функции Promise.all()
или Promise.allSettled()
для одновременной инициации всех обещаний. Например, в файле data.ts
мы используем функцию Promise.all()
в функции fetchCardData()
:
/app/lib/data.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Используя этот паттерн, вы можете:
- Начать выполнять все запросы на получение данных одновременно, что быстрее, чем ждать завершения каждого запроса в водопаде.
- Использовать собственный JavaScript-шаблон, который можно применить к любой библиотеке или фреймворку.
Однако есть один недостаток в том, чтобы полагаться только на этот JavaScript-шаблон: что произойдет, если один запрос данных будет выполняться медленнее, чем все остальные? Давайте узнаем об этом в следующей главе.
Источник — https://nextjs.org/learn/dashboard-app/fetching-data