1. Прежде чем начать
В этой лаборатории вы узнаете, как интегрировать Firebase с веб-приложением Next.js под названием Friendly Eats, которое представляет собой веб-сайт с обзорами ресторанов.
Готовое веб-приложение предлагает полезные функции, демонстрирующие, как Firebase может помочь вам создавать приложения Next.js. Эти функции включают в себя следующее:
- Автоматическая сборка и развертывание. Эта лаборатория кода использует хостинг приложений Firebase для автоматической сборки и развертывания вашего кода Next.js каждый раз, когда вы отправляете его в настроенную ветку.
- Вход и выход. Готовое веб-приложение позволяет вам входить в систему с помощью Google и выходить из нее. Вход и постоянство пользователей полностью управляются через Firebase Authentication .
- Изображения. Готовое веб-приложение позволяет вошедшим в систему пользователям загружать изображения ресторанов. Ресурсы изображений хранятся в Cloud Storage для Firebase . Firebase JavaScript SDK предоставляет общедоступный URL-адрес для загруженных изображений. Этот общедоступный URL-адрес затем сохраняется в соответствующем документе ресторана в Cloud Firestore .
- Отзывы. Готовое веб-приложение позволяет вошедшим в систему пользователям публиковать отзывы о ресторанах, состоящие из звездного рейтинга и текстового сообщения. Информация об обзоре хранится в Cloud Firestore.
- Фильтры. Готовое веб-приложение позволяет вошедшим в систему пользователям фильтровать список ресторанов по категории, местоположению и цене. Вы также можете настроить используемый метод сортировки. Доступ к данным осуществляется из Cloud Firestore, а запросы Firestore применяются на основе используемых фильтров.
Предварительные условия
- Учетная запись GitHub
- Знание Next.js и JavaScript.
Что вы узнаете
- Как использовать Firebase с маршрутизатором приложений Next.js и рендерингом на стороне сервера.
- Как сохранить изображения в Cloud Storage для Firebase.
- Как читать и записывать данные в базе данных Cloud Firestore.
- Как использовать вход в Google с помощью Firebase JavaScript SDK.
Что вам понадобится
- Гит
- Последняя стабильная версия Node.js.
- Браузер по вашему выбору, например Google Chrome.
- Среда разработки с редактором кода и терминалом.
- Учетная запись Google для создания и управления вашим проектом Firebase.
- Возможность обновить свой проект Firebase до тарифного плана Blaze.
2. Настройте среду разработки и репозиторий GitHub.
Эта лаборатория кода предоставляет начальную кодовую базу приложения и использует интерфейс командной строки Firebase.
Создайте репозиторий GitHub.
Исходный код codelab можно найти по адресу https://github.com/firebase/Friendlyeats-web . Репозиторий содержит примеры проектов для нескольких платформ. Однако в этой лаборатории кода используется только каталог nextjs-start
. Обратите внимание на следующие каталоги:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
Скопируйте папку nextjs-start
в свой репозиторий:
- Используя терминал, создайте новую папку на своем компьютере и перейдите в новый каталог:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- Используйте пакет giget npm, чтобы получить только папку
nextjs-start
:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- Отслеживайте изменения локально с помощью git:
git init git commit -a -m "codelab starting point" git branch -M main
- Создайте новый репозиторий GitHub: https://github.com/new . Назовите это как угодно.
- GitHub предоставит вам новый URL-адрес репозитория, который выглядит как
https://github.com/ / .git
https://github.com/ / .git
https://github.com/ / .git
илиgit@github.com: / .git
git@github.com: / .git
git@github.com: / .git
. Скопируйте этот URL.
- GitHub предоставит вам новый URL-адрес репозитория, который выглядит как
- Отправьте локальные изменения в новый репозиторий GitHub. Выполните следующую команду, заменив URL-адрес вашего репозитория
заполнитель. git remote add origin <your-repository-url> git push -u origin main
- Теперь вы должны увидеть стартовый код в своем репозитории GitHub.
Установите или обновите интерфейс командной строки Firebase
Выполните следующую команду, чтобы убедиться, что у вас установлен интерфейс командной строки Firebase и его версия 13.9.0 или выше:
firebase --version
Если вы видите более раннюю версию или у вас не установлен Firebase CLI, выполните команду установки:
npm install -g firebase-tools@latest
Если вам не удается установить Firebase CLI из-за ошибок разрешений, см. документацию npm или воспользуйтесь другим вариантом установки .
Войдите в Firebase
- Выполните следующую команду, чтобы войти в интерфейс командной строки Firebase:
firebase login
- В зависимости от того, хотите ли вы, чтобы Firebase собирала данные, введите
Y
илиN
- В браузере выберите свою учетную запись Google и нажмите «Разрешить» .
3. Настройте свой проект Firebase
В этом разделе вы настроите проект Firebase и свяжете с ним веб-приложение Firebase. Вы также настроите службы Firebase, используемые примером веб-приложения.
Создать проект Firebase
- В консоли Firebase нажмите «Добавить проект» .
- В текстовом поле Введите имя проекта введите
FriendlyEats Codelab
(или имя проекта по вашему выбору), а затем нажмите Продолжить . - В модальном окне «Подтвердить план выставления счетов Firebase» подтвердите, что это план Blaze , а затем нажмите «Подтвердить план».
- Для этой лаборатории вам не нужен Google Analytics, поэтому отключите параметр «Включить Google Analytics для этого проекта» .
- Нажмите Создать проект .
- Подождите, пока ваш проект будет подготовлен, а затем нажмите «Продолжить» .
- В проекте Firebase перейдите в «Настройки проекта» . Запишите идентификатор своего проекта, потому что он понадобится вам позже. Этот уникальный идентификатор определяет ваш проект (например, в интерфейсе командной строки Firebase).
Обновите тарифный план Firebase
Чтобы использовать хостинг приложений Firebase и облачное хранилище для Firebase, ваш проект Firebase должен находиться на тарифном плане с оплатой по факту использования (Blaze) , что означает, что он связан с учетной записью выставления счетов в облаке .
- Для учетной записи Cloud Billing требуется способ оплаты, например кредитная карта.
- Если вы новичок в Firebase и Google Cloud, проверьте, имеете ли вы право на получение кредита в размере 300 долларов США и бесплатную пробную платежную учетную запись Cloud .
- Если вы выполняете эту лабораторную работу в рамках мероприятия, спросите у организатора, есть ли у него какие-либо облачные кредиты.
Чтобы обновить проект до плана Blaze, выполните следующие действия:
- В консоли Firebase выберите обновление плана .
- Выберите план Blaze. Следуйте инструкциям на экране, чтобы связать учетную запись Cloud Billing с вашим проектом.
Если вам нужно было создать учетную запись Cloud Billing в рамках этого обновления, вам может потребоваться вернуться к процессу обновления в консоли Firebase, чтобы завершить обновление.
Добавьте веб-приложение в свой проект Firebase
- Перейдите к обзору проекта в проекте Firebase и нажмите Веб .
Если в вашем проекте уже зарегистрированы приложения, нажмите «Добавить приложение», чтобы увидеть значок Интернета. - В текстовом поле «Псевдоним приложения» введите запоминающийся псевдоним приложения, например
My Next.js app
. - Оставьте флажок «Также настроить хостинг Firebase для этого приложения» снятым.
- Нажмите «Зарегистрировать приложение» > «Далее» > «Далее» > «Продолжить работу с консолью» .
Настройте сервисы Firebase в консоли Firebase
Настройка аутентификации
- В консоли Firebase перейдите к Authentication .
- Нажмите «Начать» .
- В столбце «Дополнительные поставщики» нажмите Google > Включить .
- В текстовом поле Общедоступное имя проекта введите запоминающееся имя, например
My Next.js app
. - В раскрывающемся списке «Электронная почта поддержки проекта» выберите свой адрес электронной почты.
- Нажмите Сохранить .
Настройте Cloud Firestore
- На левой панели консоли Firebase разверните «Сборка» и выберите «База данных Firestore» .
- Нажмите Создать базу данных .
- Оставьте для идентификатора базы данных значение
(default)
. - Выберите местоположение для вашей базы данных, затем нажмите «Далее» .
Для реального приложения вам нужно выбрать местоположение, наиболее близкое к вашим пользователям. - Нажмите «Запустить в тестовом режиме» . Прочтите отказ от ответственности о правилах безопасности.
Позже в этой лабораторной работе вы добавите правила безопасности для защиты ваших данных. Не распространяйте и не публикуйте приложение без добавления правил безопасности для вашей базы данных. - Нажмите Создать .
Настройте облачное хранилище для Firebase
- На левой панели консоли Firebase разверните «Сборка» и выберите «Хранилище» .
- Нажмите «Начать» .
- Выберите расположение для сегмента хранилища по умолчанию.
Сегменты вUS-WEST1
,US-CENTRAL1
иUS-EAST1
могут использовать преимущества уровня «Всегда бесплатно» для Google Cloud Storage. Во всех остальных местах сегменты соответствуют ценам и использованию Google Cloud Storage . - Нажмите «Запустить в тестовом режиме» . Прочтите отказ от ответственности о правилах безопасности.
Позже в этой лабораторной работе вы добавите правила безопасности для защиты ваших данных. Не распространяйте и не публикуйте приложение без добавления правил безопасности для сегмента хранилища. - Нажмите Создать .
4. Просмотрите начальную кодовую базу
В этом разделе вы рассмотрите несколько областей начальной кодовой базы приложения, к которым вы добавите функциональные возможности в этой лаборатории кода.
Структура папок и файлов
В следующей таблице представлен обзор структуры папок и файлов приложения:
Папки и файлы | Описание |
| Компоненты React для фильтров, заголовков, сведений о ресторанах и обзоров. |
| Вспомогательные функции, которые не обязательно привязаны к React или Next.js. |
| Код, специфичный для Firebase, и конфигурация Firebase |
| Статические ресурсы в веб-приложении, например значки. |
| Маршрутизация с помощью маршрутизатора приложений Next.js |
| Обработчик маршрута API |
| Зависимости проекта с npm |
| Конфигурация, специфичная для Next.js (действия сервера включены ) |
| Конфигурация языкового сервиса JavaScript |
Серверные и клиентские компоненты
Это веб-приложение Next.js, использующее App Router . Серверный рендеринг используется во всем приложении. Например, файл src/app/page.js
— это серверный компонент, отвечающий за главную страницу. Файл src/components/RestaurantListings.jsx
представляет собой клиентский компонент, обозначенный директивой "use client"
в начале файла.
Операторы импорта
Вы можете заметить такие операторы импорта:
import RatingPicker from "@/src/components/RatingPicker.jsx";
Приложение использует символ @
, чтобы избежать неуклюжих относительных путей импорта, и это становится возможным благодаря псевдонимам путей .
API-интерфейсы Firebase
Весь код Firebase API заключен в каталог src/lib/firebase
. Отдельные компоненты React затем импортируют обернутые функции из каталога src/lib/firebase
, а не импортируют функции Firebase напрямую.
Макетные данные
Данные о ложном ресторане и отзывах содержатся в файле src/lib/randomData.js
. Данные из этого файла собираются в коде файла src/lib/fakeRestaurants.js
.
5. Создайте серверную часть хостинга приложений.
В этом разделе вы настроите серверную часть хостинга приложений для просмотра ветки в вашем репозитории git.
К концу этого раздела у вас будет серверная часть хостинга приложений, подключенная к вашему репозиторию в GitHub, которая будет автоматически пересобирать и развертывать новую версию вашего приложения всякий раз, когда вы отправляете новый коммит в свою main
ветку.
Развертывание правил безопасности
В коде уже есть наборы правил безопасности для Firestore и Cloud Storage для Firebase. После развертывания правил безопасности данные в вашей базе данных и корзине будут лучше защищены от неправомерного использования.
- В своем терминале настройте CLI для использования проекта Firebase, который вы создали ранее:
firebase use --add
Когда будет предложено ввести псевдоним, введитеfriendlyeats-codelab
. - Чтобы развернуть эти правила безопасности, запустите эту команду в своем терминале:
firebase deploy --only firestore:rules,storage
- Если вас спросят:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, нажмитеEnter
чтобы выбрать Да .
Добавьте конфигурацию Firebase в код вашего веб-приложения.
- В консоли Firebase перейдите к настройкам проекта .
- На панели установки и конфигурации SDK нажмите «Добавить приложение» и щелкните значок скобок кода.> для регистрации нового веб-приложения.
- В конце процесса создания веб-приложения скопируйте переменную
firebaseConfig
, а также ее свойства и их значения. - Откройте файл
apphosting.yaml
в редакторе кода и заполните значения переменных среды значениями конфигурации из консоли Firebase. - В файле замените существующие свойства теми, которые вы скопировали.
- Сохраните файл.
Создать серверную часть
- Перейдите на страницу хостинга приложений в консоли Firebase:
- Нажмите «Начать», чтобы начать процесс создания серверной части. Настройте свой бэкэнд следующим образом:
- Следуйте инструкциям на первом шаге, чтобы подключить созданный ранее репозиторий GitHub.
- Установите параметры развертывания:
- Сохраните корневой каталог как
/
- Установите живую ветку на
main
- Включить автоматическое внедрение
- Сохраните корневой каталог как
- Назовите свой бэкэнд
friendlyeats-codelab
. - В разделе «Создание или связывание веб-приложения Firebase» выберите веб-приложение, которое вы настроили ранее, из раскрывающегося списка «Выберите существующее веб-приложение Firebase».
- Нажмите «Завершить и развернуть». Через мгновение вы перейдете на новую страницу, где сможете увидеть состояние вашего нового бэкэнда хостинга приложений!
- После завершения развертывания выберите бесплатный домен в разделе «домены». Прежде чем начать работу, может потребоваться несколько минут из-за распространения DNS.
Вы развернули исходное веб-приложение! Каждый раз, когда вы отправляете новый коммит в main
ветку вашего репозитория GitHub, вы увидите, что в консоли Firebase начинается новая сборка и развертывание, и ваш сайт будет автоматически обновляться после завершения развертывания.
6. Добавьте аутентификацию в веб-приложение.
В этом разделе вы добавите аутентификацию в веб-приложение, чтобы иметь возможность войти в него.
Реализация функций входа и выхода.
- В файле
src/lib/firebase/auth.js
замените функцииonAuthStateChanged
,signInWithGoogle
иsignOut
следующим кодом:
export function onAuthStateChanged(cb) {
return _onAuthStateChanged(auth, cb);
}
export async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
try {
await signInWithPopup(auth, provider);
} catch (error) {
console.error("Error signing in with Google", error);
}
}
export async function signOut() {
try {
return auth.signOut();
} catch (error) {
console.error("Error signing out with Google", error);
}
}
Этот код использует следующие API Firebase:
API Firebase | Описание |
Создает экземпляр поставщика аутентификации Google. | |
Запускает процесс аутентификации на основе диалога. | |
Выполняет выход пользователя. |
В файле src/components/Header.jsx
код уже вызывает функции signInWithGoogle
и signOut
.
- Создайте коммит с сообщением о коммите «Добавление аутентификации Google» и отправьте его в свой репозиторий GitHub. 1. Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- В веб-приложении обновите страницу и нажмите «Войти через Google» . Веб-приложение не обновляется, поэтому неясно, удалось ли войти в систему.
Отправить состояние аутентификации на сервер
Чтобы передать состояние аутентификации на сервер, мы будем использовать сервис-воркера . Замените функции fetchWithFirebaseHeaders
и getAuthIdToken
следующим кодом:
async function fetchWithFirebaseHeaders(request) {
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const installations = getInstallations(app);
const headers = new Headers(request.headers);
const [authIdToken, installationToken] = await Promise.all([
getAuthIdToken(auth),
getToken(installations),
]);
headers.append("Firebase-Instance-ID-Token", installationToken);
if (authIdToken) headers.append("Authorization", `Bearer ${authIdToken}`);
const newRequest = new Request(request, { headers });
return await fetch(newRequest);
}
async function getAuthIdToken(auth) {
await auth.authStateReady();
if (!auth.currentUser) return;
return await getIdToken(auth.currentUser);
}
Чтение состояния аутентификации на сервере
Мы будем использовать FirebaseServerApp для отражения состояния аутентификации клиента на сервере.
Откройте src/lib/firebase/serverApp.js
и замените функцию getAuthenticatedAppForUser
:
export async function getAuthenticatedAppForUser() {
const idToken = headers().get("Authorization")?.split("Bearer ")[1];
console.log('firebaseConfig', JSON.stringify(firebaseConfig));
const firebaseServerApp = initializeServerApp(
firebaseConfig,
idToken
? {
authIdToken: idToken,
}
: {}
);
const auth = getAuth(firebaseServerApp);
await auth.authStateReady();
return { firebaseServerApp, currentUser: auth.currentUser };
}
Подписаться на изменения аутентификации
Чтобы подписаться на изменения аутентификации, выполните следующие действия:
- Перейдите к файлу
src/components/Header.jsx
. - Замените функцию
useUserSession
следующим кодом:
function useUserSession(initialUser) {
// The initialUser comes from the server via a server component
const [user, setUser] = useState(initialUser);
const router = useRouter();
// Register the service worker that sends auth state back to server
// The service worker is built with npm run build-service-worker
useEffect(() => {
if ("serviceWorker" in navigator) {
const serializedFirebaseConfig = encodeURIComponent(JSON.stringify(firebaseConfig));
const serviceWorkerUrl = `/auth-service-worker.js?firebaseConfig=${serializedFirebaseConfig}`
navigator.serviceWorker
.register(serviceWorkerUrl)
.then((registration) => console.log("scope is: ", registration.scope));
}
}, []);
useEffect(() => {
const unsubscribe = onAuthStateChanged((authUser) => {
setUser(authUser)
})
return () => unsubscribe()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
onAuthStateChanged((authUser) => {
if (user === undefined) return
// refresh when user changed to ease testing
if (user?.email !== authUser?.email) {
router.refresh()
}
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user])
return user;
}
Этот код использует перехватчик состояния React для обновления пользователя, когда функция onAuthStateChanged
указывает, что произошло изменение состояния аутентификации.
Проверьте изменения
Корневой макет в файле src/app/layout.js
отображает заголовок и передает пользователя, если он доступен, в качестве реквизита.
<Header initialUser={currentUser?.toJSON()} />
Это означает, что компонент <Header>
отображает пользовательские данные, если они доступны, во время работы сервера. Если в течение жизненного цикла страницы после ее начальной загрузки происходят какие-либо обновления аутентификации, их обрабатывает обработчик onAuthStateChanged
.
Теперь пришло время развернуть новую сборку и проверить то, что вы собрали.
- Создайте коммит с сообщением «Показать состояние входа» и отправьте его в свой репозиторий GitHub.
- Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- Проверьте новое поведение аутентификации:
- В браузере обновите веб-приложение. Ваше отображаемое имя появится в заголовке.
- Выйдите из системы и войдите снова. Страница обновляется в режиме реального времени без обновления страницы. Вы можете повторить этот шаг с разными пользователями.
- Необязательно: щелкните веб-приложение правой кнопкой мыши, выберите «Просмотреть источник страницы » и найдите отображаемое имя. Он появляется в необработанном исходном HTML-коде, возвращаемом с сервера.
7. Просмотр информации о ресторане
Веб-приложение включает в себя фиктивные данные о ресторанах и обзоры.
Добавьте один или несколько ресторанов
Чтобы вставить данные макета ресторана в локальную базу данных Cloud Firestore, выполните следующие действия:
- В веб-приложении выберите >Добавьте образцы ресторанов .
- В консоли Firebase на странице базы данных Firestore выберите рестораны . В коллекции ресторанов вы видите документы верхнего уровня, каждый из которых представляет ресторан.
- Щелкните несколько документов, чтобы изучить свойства документа ресторана.
Показать список ресторанов
В вашей базе данных Cloud Firestore теперь есть рестораны, которые может отображать веб-приложение Next.js.
Чтобы определить код получения данных, выполните следующие действия:
- В файле
src/app/page.js
найдите серверный компонент<Home />
и просмотрите вызов функцииgetRestaurants
, которая получает список ресторанов во время работы сервера. Вы реализуете функциюgetRestaurants
на следующих шагах. - В файле
src/lib/firebase/firestore.js
замените функцииapplyQueryFilters
иgetRestaurants
следующим кодом:
function applyQueryFilters(q, { category, city, price, sort }) {
if (category) {
q = query(q, where("category", "==", category));
}
if (city) {
q = query(q, where("city", "==", city));
}
if (price) {
q = query(q, where("price", "==", price.length));
}
if (sort === "Rating" || !sort) {
q = query(q, orderBy("avgRating", "desc"));
} else if (sort === "Review") {
q = query(q, orderBy("numRatings", "desc"));
}
return q;
}
export async function getRestaurants(db = db, filters = {}) {
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const results = await getDocs(q);
return results.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
}
- Создайте коммит с сообщением «Прочитать список ресторанов из Firestore» и отправьте его в свой репозиторий GitHub.
- Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- В веб-приложении обновите страницу. Изображения ресторанов отображаются на странице в виде плиток.
Убедитесь, что списки ресторанов загружаются во время работы сервера.
При использовании платформы Next.js может быть неочевидно, когда данные загружаются во время выполнения на сервере или во время выполнения на стороне клиента.
Чтобы убедиться, что списки ресторанов загружаются во время работы сервера, выполните следующие действия:
- В веб-приложении откройте DevTools и отключите JavaScript .
- Обновите веб-приложение. Списки ресторанов все еще загружаются. Информация о ресторане возвращается в ответе сервера. Когда JavaScript включен, информация о ресторане передается через клиентский код JavaScript.
- В DevTools повторно включите JavaScript .
Слушайте обновления ресторанов с помощью прослушивателей снимков Cloud Firestore
В предыдущем разделе вы видели, как начальный набор ресторанов загружается из файла src/app/page.js
. Файл src/app/page.js
является серверным компонентом и отображается на сервере, включая код получения данных Firebase.
Файл src/components/RestaurantListings.jsx
является клиентским компонентом и может быть настроен для гидратации разметки, отображаемой на сервере.
Чтобы настроить файл src/components/RestaurantListings.jsx
для гидратации разметки, отображаемой на сервере, выполните следующие действия:
- В файле
src/components/RestaurantListings.jsx
обратите внимание на следующий код, который уже написан для вас:
useEffect(() => {
const unsubscribe = getRestaurantsSnapshot(data => {
setRestaurants(data);
}, filters);
return () => {
unsubscribe();
};
}, [filters]);
Этот код вызывает функцию getRestaurantsSnapshot()
, аналогичную функции getRestaurants()
, которую вы реализовали на предыдущем шаге. Однако эта функция моментального снимка предоставляет механизм обратного вызова, поэтому обратный вызов вызывается каждый раз, когда в коллекцию ресторана вносится изменение.
- В файле
src/lib/firebase/firestore.js
замените функциюgetRestaurantsSnapshot()
следующим кодом:
export function getRestaurantsSnapshot(cb, filters = {}) {
if (typeof cb !== "function") {
console.log("Error: The callback parameter is not a function");
return;
}
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const unsubscribe = onSnapshot(q, querySnapshot => {
const results = querySnapshot.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
cb(results);
});
return unsubscribe;
}
Изменения, внесенные на странице базы данных Firestore , теперь отражаются в веб-приложении в режиме реального времени.
- Создайте коммит с сообщением «Слушайте обновления ресторана в реальном времени» и отправьте его в свой репозиторий GitHub.
- Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- В веб-приложении выберите >Добавьте образцы ресторанов . Если функция моментального снимка реализована правильно, рестораны отображаются в режиме реального времени без обновления страницы.
8. Сохраняйте отзывы, отправленные пользователями, из веб-приложения.
- В файле
src/lib/firebase/firestore.js
замените функциюupdateWithRating()
следующим кодом:
const updateWithRating = async (
transaction,
docRef,
newRatingDocument,
review
) => {
const restaurant = await transaction.get(docRef);
const data = restaurant.data();
const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
const newSumRating = (data?.sumRating || 0) + Number(review.rating);
const newAverage = newSumRating / newNumRatings;
transaction.update(docRef, {
numRatings: newNumRatings,
sumRating: newSumRating,
avgRating: newAverage,
});
transaction.set(newRatingDocument, {
...review,
timestamp: Timestamp.fromDate(new Date()),
});
};
Этот код вставляет новый документ Firestore, представляющий новый обзор. Код также обновляет существующий документ Firestore, представляющий ресторан, с обновленными значениями количества оценок и среднего рассчитанного рейтинга.
- Замените функцию
addReviewToRestaurant()
следующим кодом:
export async function addReviewToRestaurant(db, restaurantId, review) {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!review) {
throw new Error("A valid review has not been provided.");
}
try {
const docRef = doc(collection(db, "restaurants"), restaurantId);
const newRatingDocument = doc(
collection(db, `restaurants/${restaurantId}/ratings`)
);
// corrected line
await runTransaction(db, transaction =>
updateWithRating(transaction, docRef, newRatingDocument, review)
);
} catch (error) {
console.error(
"There was an error adding the rating to the restaurant",
error
);
throw error;
}
}
Реализация действия сервера Next.js
Серверное действие Next.js предоставляет удобный API для доступа к данным формы, например data.get("text")
для получения текстового значения из полезных данных отправки формы.
Чтобы использовать действие сервера Next.js для обработки отправки формы обзора, выполните следующие действия:
- В файле
src/components/ReviewDialog.jsx
найдите атрибутaction
в элементе<form>
.
<form action={handleReviewFormSubmission}>
Значение атрибута action
относится к функции, которую вы реализуете на следующем шаге.
- В файле
src/app/actions.js
замените функциюhandleReviewFormSubmission()
следующим кодом:
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
const { app } = await getAuthenticatedAppForUser();
const db = getFirestore(app);
await addReviewToRestaurant(db, data.get("restaurantId"), {
text: data.get("text"),
rating: data.get("rating"),
// This came from a hidden form field.
userId: data.get("userId"),
});
}
Добавить отзыв о ресторане
Вы реализовали поддержку отправки отзывов, поэтому теперь вы можете убедиться, что ваши отзывы правильно вставлены в Cloud Firestore.
Чтобы добавить отзыв и убедиться, что он вставлен в Cloud Firestore, выполните следующие действия:
- Создайте коммит с сообщением «Разрешить пользователям отправлять обзоры ресторанов» и отправьте его в свой репозиторий GitHub.
- Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- Обновите веб-приложение и выберите ресторан на главной странице.
- На странице ресторана нажмите .
- Выберите звездный рейтинг.
- Напишите отзыв.
- Нажмите «Отправить» . Ваш отзыв появится вверху списка отзывов.
- В Cloud Firestore найдите на панели «Добавить документ» документ ресторана, который вы просматривали, и выберите его.
- На панели «Начать сбор» выберите рейтинги .
- На панели «Добавить документ» найдите документ для проверки и убедитесь, что он вставлен должным образом.
9. Сохраняйте файлы, загруженные пользователем, из веб-приложения.
В этом разделе вы добавляете функциональные возможности, позволяющие заменять изображение, связанное с рестораном, при входе в систему. Вы загружаете изображение в Firebase Storage и обновляете URL-адрес изображения в документе Cloud Firestore, который представляет ресторан.
Чтобы сохранить файлы, загруженные пользователем из веб-приложения, выполните следующие действия:
- В файле
src/components/Restaurant.jsx
обратите внимание на код, который запускается, когда пользователь загружает файл:
async function handleRestaurantImage(target) {
const image = target.files ? target.files[0] : null;
if (!image) {
return;
}
const imageURL = await updateRestaurantImage(id, image);
setRestaurant({ ...restaurant, photo: imageURL });
}
Никаких изменений не требуется, но вы реализуете поведение функции updateRestaurantImage()
на следующих шагах.
- В файле
src/lib/firebase/storage.js
замените функцииupdateRestaurantImage()
иuploadImage()
следующим кодом:
export async function updateRestaurantImage(restaurantId, image) {
try {
if (!restaurantId)
throw new Error("No restaurant ID has been provided.");
if (!image || !image.name)
throw new Error("A valid image has not been provided.");
const publicImageUrl = await uploadImage(restaurantId, image);
await updateRestaurantImageReference(restaurantId, publicImageUrl);
return publicImageUrl;
} catch (error) {
console.error("Error processing request:", error);
}
}
async function uploadImage(restaurantId, image) {
const filePath = `images/${restaurantId}/${image.name}`;
const newImageRef = ref(storage, filePath);
await uploadBytesResumable(newImageRef, image);
return await getDownloadURL(newImageRef);
}
Функция updateRestaurantImageReference()
уже реализована для вас. Эта функция обновляет существующий документ ресторана в Cloud Firestore, добавляя обновленный URL-адрес изображения.
Проверьте функциональность загрузки изображений
Чтобы убедиться, что изображение загружается должным образом, выполните следующие действия:
- Создайте коммит с сообщением «Разрешить пользователям изменять фотографии каждого ресторана» и отправьте его в свой репозиторий GitHub.
- Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- В веб-приложении убедитесь, что вы вошли в систему, и выберите ресторан.
- Нажмите и загрузите изображение из вашей файловой системы. Ваше изображение покидает вашу локальную среду и загружается в облачное хранилище. Изображение появляется сразу после его загрузки.
- Перейдите в облачное хранилище для Firebase.
- Перейдите в папку, представляющую ресторан. Загруженное вами изображение существует в папке.
10. Обобщите обзоры ресторанов с помощью генеративного искусственного интеллекта
В этом разделе вы добавите функцию сводки отзывов, чтобы пользователь мог быстро понять, что все думают о ресторане, без необходимости читать каждый отзыв.
Сохраните ключ API Gemini в Cloud Secret Manager.
- Чтобы использовать API Gemini, вам понадобится ключ API. Создайте ключ в Google AI Studio .
- Хостинг приложений интегрируется с Cloud Secret Manager , что позволяет вам безопасно хранить конфиденциальные значения, такие как ключи API:
- В терминале выполните команду для создания нового секрета:
firebase apphosting:secrets:set gemini-api-key
- Когда будет предложено ввести секретное значение, скопируйте и вставьте ключ Gemini API из Google AI Studio.
- Когда вас спросят, следует ли добавить новый секрет в
apphosting.yaml
, введитеY
чтобы принять его.
Ваш ключ API Gemini теперь надежно хранится в диспетчере Cloud Secret и доступен для серверной части вашего хостинга приложений.
Внедрить компонент сводки обзора
- В
src/components/Reviews/ReviewSummary.jsx
замените функциюGeminiSummary
следующим кодом:export async function GeminiSummary({ restaurantId }) { const { firebaseServerApp } = await getAuthenticatedAppForUser(); const reviews = await getReviewsByRestaurantId( getFirestore(firebaseServerApp), restaurantId ); const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); const model = genAI.getGenerativeModel({ model: "gemini-pro"}); const reviewSeparator = "@"; const prompt = ` Based on the following restaurant reviews, where each review is separated by a '${reviewSeparator}' character, create a one-sentence summary of what people think of the restaurant. Here are the reviews: ${reviews.map(review => review.text).join(reviewSeparator)} `; try { const result = await model.generateContent(prompt); const response = await result.response; const text = response.text(); return ( <div className="restaurant__review_summary"> <p>{text}</p> <p>✨ Summarized with Gemini</p> </div> ); } catch (e) { console.error(e); return <p>Error contacting Gemini</p>; } }
- Создайте коммит с сообщением «Используйте AI для обобщения обзоров» и отправьте его в свой репозиторий GitHub.
- Откройте страницу хостинга приложений в консоли Firebase и дождитесь завершения нового развертывания.
- Откройте страницу ресторана. Вверху вы должны увидеть краткое изложение всех отзывов на странице в одно предложение.
- Добавьте новый отзыв и обновите страницу. Вы должны увидеть изменение сводки.
11. Заключение
Поздравляем! Вы узнали, как использовать Firebase для добавления функций и возможностей в приложение Next.js. В частности, вы использовали следующее:
- Хостинг приложений Firebase для автоматического создания и развертывания кода Next.js каждый раз, когда вы отправляете его в настроенную ветку.
- Аутентификация Firebase для включения функций входа и выхода.
- Cloud Firestore для данных о ресторанах и данных обзоров ресторанов.
- Облачное хранилище для Firebase для изображений ресторанов.